/******************************************************************************
 * Copyright 2007 - 2021 Realtek Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *****************************************************************************/
 
#include "drv_types.h"
#include "rtw_wlan_config.h"
#include "osdep_service.h"
//#include "rtw_mp_ioctl.h" #include <rtw_mp.h>
#include "rtw_ap.h"
#include "hal_data.h"
typedef int (*wlan_conf_handler) (void *dev,struct rtw_wc_param *iwcp);
extern struct net_device*	rtw_netdev[1];

// combo scan
#define WEXT_CSCAN_AMOUNT 9
#define WEXT_CSCAN_BUF_LEN		360
#define WEXT_CSCAN_HEADER		"CSCAN S\x01\x00\x00S\x00"
#define WEXT_CSCAN_HEADER_SIZE		12
#define WEXT_CSCAN_SSID_SECTION		'S'
#define WEXT_CSCAN_CHANNEL_SECTION	'C'
#define WEXT_CSCAN_NPROBE_SECTION	'N'
#define WEXT_CSCAN_ACTV_DWELL_SECTION	'A'
#define WEXT_CSCAN_PASV_DWELL_SECTION	'P'
#define WEXT_CSCAN_HOME_DWELL_SECTION	'H'
#define WEXT_CSCAN_TYPE_SECTION		'T'

#define MAX_CUSTOM_LEN 64

int32_t HdfWifiEventScanDone(const struct NetDevice *netDev, WifiScanStatus status);
int32_t HdfWifiEventInformBssFrame(const struct NetDevice *netDev,
    const struct WlanChannel *channel, const struct ScannedBssInfo *bssInfo);
int32_t HdfWifiEventConnectResult(const struct NetDevice *netDev, const struct ConnetResult *result);
int32_t HdfWifiEventDisconnected(const struct NetDevice *netDev, uint16_t reason, const uint8_t *ie, uint32_t len);


/* Common parser for WPA and WPA2. skips the OUI type comparison */
static int wlan_get_wpa_ciphers(u8 *ie, s16 ie_len, u8 *gcipher,u8 *pcipher)
{
    int i, count;

    /* Get group cipher */
    if (ie_len >= 4) {
        if (ie[3] == 0x02) {
            *gcipher = WC_WPA_UCIPHER_TKIP;
        } else if (ie[3] == 0x04) {
            *gcipher = WC_WPA_UCIPHER_AES;
        }
        ie += 4;
        ie_len -= 4;
    }

    /* Get pairwise cipher list */
    if (ie_len >= 2) {
        *pcipher = 0;
        count = ie[0] | (ie[1] << 8);
        ie += 2;
        ie_len -= 2;
        if (count == 0 || ie_len < (count * 4)) {
            return -1;
        }
        for (i = 0; i < count; i++) {
            if (ie[3] == 0x02) {
                *pcipher |= WC_WPA_UCIPHER_TKIP;
            } else if (ie[3] == 0x04) {
                *pcipher |= WC_WPA_UCIPHER_AES;
            }
            ie += 4;
            ie_len -= 4;
        }
    }

    return 0;
}

static int translate_scan(_adapter *padapter, 
                            rtw_wc_bss_info *bss_info,
                            struct wlan_network *pnetwork)
{
    u16 cap;
    u32 ht_ielen = 0;
    char custom[MAX_CUSTOM_LEN];
    char *p;
    u16 max_rate=0, rate, ht_cap=_FALSE;
    u32 i = 0;	
    u8 bw_40MHz=0, short_GI=0;
    u16 mcs_rate=0;
#ifdef CONFIG_P2P
    struct wifidirect_info	*pwdinfo = &padapter->wdinfo;
#endif //CONFIG_P2P

#ifdef CONFIG_P2P
#ifdef CONFIG_WFD
    if ( SCAN_RESULT_ALL == pwdinfo->wfd_info->scan_result_type )
    {

    }
    else if ( ( SCAN_RESULT_P2P_ONLY == pwdinfo->wfd_info->scan_result_type ) || 
            ( SCAN_RESULT_WFD_TYPE == pwdinfo->wfd_info->scan_result_type ) )
#endif // CONFIG_WFD
    {
        if(!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE))
        {
            u32	blnGotP2PIE = _FALSE;

            //	User is doing the P2P device discovery
            //	The prefix of SSID should be "DIRECT-" and the IE should contains the P2P IE.
            //	If not, the driver should ignore this AP and go to the next AP.

            //	Verifying the SSID
            if ( _rtw_memcmp( pnetwork->network.Ssid.Ssid, pwdinfo->p2p_wildcard_ssid, P2P_WILDCARD_SSID_LEN ) )
            {
                u32	p2pielen = 0;

                if (pnetwork->network.Reserved[0] == 2) { // Probe Request
                    //	Verifying the P2P IE
                    if ( rtw_get_p2p_ie( pnetwork->network.IEs, pnetwork->network.IELength, NULL, &p2pielen) )
                    {
                        blnGotP2PIE = _TRUE;
                    }
                } else { // Beacon or Probe Respones
                    //	Verifying the P2P IE
                    if ( rtw_get_p2p_ie( &pnetwork->network.IEs[12], pnetwork->network.IELength - 12, NULL, &p2pielen) )
                    {
                        blnGotP2PIE = _TRUE;
                    }
                }
            }

            if ( blnGotP2PIE == _FALSE )
            {
                return 1;
            }

        }
    }

#ifdef CONFIG_WFD
    if ( SCAN_RESULT_WFD_TYPE == pwdinfo->wfd_info->scan_result_type )
    {
        u32	blnGotWFD = _FALSE;
        u8	wfd_ie[ 128 ] = { 0x00 };
        uint	wfd_ielen = 0;

        if ( rtw_get_wfd_ie( &pnetwork->network.IEs[12], pnetwork->network.IELength - 12,  wfd_ie, &wfd_ielen ) )
        {
            u8	wfd_devinfo[ 6 ] = { 0x00 };
            uint	wfd_devlen = 6;

            if ( rtw_get_wfd_attr_content( wfd_ie, wfd_ielen, WFD_ATTR_DEVICE_INFO, wfd_devinfo, &wfd_devlen) )
            {
                if ( pwdinfo->wfd_info->wfd_device_type == WFD_DEVINFO_PSINK )
                {
                    //	the first two bits will indicate the WFD device type
                    if ( ( wfd_devinfo[ 1 ] & 0x03 ) == WFD_DEVINFO_SOURCE )
                    {
                        //	If this device is Miracast PSink device, the scan reuslt should just provide the Miracast source.
                        blnGotWFD = _TRUE;
                    }
                }
                else if ( pwdinfo->wfd_info->wfd_device_type == WFD_DEVINFO_SOURCE )
                {
                    //	the first two bits will indicate the WFD device type
                    if ( ( wfd_devinfo[ 1 ] & 0x03 ) == WFD_DEVINFO_PSINK )
                    {
                        //	If this device is Miracast source device, the scan reuslt should just provide the Miracast PSink.
                        //	Todo: How about the SSink?!
                        blnGotWFD = _TRUE;
                    }
                }
            }
        }

        if ( blnGotWFD == _FALSE )
        {
            return 1;
        }
    }
#endif // CONFIG_WFD

#endif //CONFIG_P2P

    /* memset to zero */
    memset(bss_info, 0, sizeof(rtw_wc_bss_info));

    /*  AP MAC address  */
    _rtw_memcpy(&bss_info->bssid, pnetwork->network.MacAddress, ETH_ALEN);

    /* Add the ESSID */
    _rtw_memcpy(bss_info->ssid, pnetwork->network.Ssid.Ssid,
            pnetwork->network.Ssid.SsidLength);
    bss_info->ssid_len = pnetwork->network.Ssid.SsidLength;
   	
    //parsing HT_CAP_IE
    p = (char *)rtw_get_ie(&pnetwork->network.IEs[12], _HT_CAPABILITY_IE_, 
            (sint *)&ht_ielen, pnetwork->network.IELength-12);

    if(p && ht_ielen>0)
    {
        struct rtw_ieee80211_ht_cap *pht_capie;
        ht_cap = _TRUE;			
        pht_capie = (struct rtw_ieee80211_ht_cap *)(p+2);		
        _rtw_memcpy(&mcs_rate , pht_capie->supp_mcs_set, 2);
        bw_40MHz = (pht_capie->cap_info&IEEE80211_HT_CAP_SUP_WIDTH) ? 1:0;
        short_GI = (pht_capie->cap_info&(IEEE80211_HT_CAP_SGI_20|IEEE80211_HT_CAP_SGI_40)) ? 1:0;
    }

    /* Add the protocol name */
    if ((rtw_is_cckratesonly_included((u8*)&pnetwork->network.SupportedRates)) == _TRUE)		
    {
        if(ht_cap == _TRUE)
            _rtw_memcpy(bss_info->name,"IEEE 802.11bn",14);
        else
            _rtw_memcpy(bss_info->name,"IEEE 802.11b",13);
    }	
    else if ((rtw_is_cckrates_included((u8*)&pnetwork->network.SupportedRates)) == _TRUE)	
    {
        if(ht_cap == _TRUE)
            _rtw_memcpy(bss_info->name,"IEEE 802.11bgn",15);
        else
            _rtw_memcpy(bss_info->name,"IEEE 802.11bg",14);
    }	
    else
    {
        if(pnetwork->network.Configuration.DSConfig > 14)
        {
            if(ht_cap == _TRUE)
                _rtw_memcpy(bss_info->name,"IEEE 802.11an",14);
            else
                _rtw_memcpy(bss_info->name,"IEEE 802.11a",13);
        }
        else
        {
            if(ht_cap == _TRUE)
                _rtw_memcpy(bss_info->name,"IEEE 802.11gn",14);
            else
                _rtw_memcpy(bss_info->name,"IEEE 802.11g",13);
        }
    }	

    /* Add mode */
    _rtw_memcpy((u8 *)&cap, rtw_get_capability_from_ie(pnetwork->network.IEs), 2);

    cap = rtw_le16_to_cpu(cap);

    if(cap & (WLAN_CAPABILITY_IBSS |WLAN_CAPABILITY_BSS)){
        if (cap & WLAN_CAPABILITY_BSS)
            bss_info->mode = WC_FLAG_MODE_MASTER;
        else
            bss_info->mode = WC_FLAG_MODE_ADHOC;

    }

    if(pnetwork->network.Configuration.DSConfig<1 /*|| pnetwork->network.Configuration.DSConfig>14*/)
        pnetwork->network.Configuration.DSConfig = 1;

    /* Add frequency/channel */
    bss_info->channel = pnetwork->network.Configuration.DSConfig; 

    /* Add encryption capability */
    if (cap & WLAN_CAPABILITY_PRIVACY)
        bss_info->privacy = WC_FLAG_ENCODE_ENABLED;
    else
        bss_info->privacy = WC_FLAG_ENCODE_DISABLED;

    /*Add basic and extended rates */
    max_rate = 0;
    p = custom;
    p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), " Rates (Mb/s): ");
    while(pnetwork->network.SupportedRates[i]!=0)
    {
        rate = pnetwork->network.SupportedRates[i]&0x7F; 
        if (rate > max_rate)
            max_rate = rate;
        p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
                "%d%s ", rate >> 1, (rate & 1) ? ".5" : "");
        i++;
    }

    if(ht_cap == _TRUE)
    {
        if(mcs_rate&0x8000)//MCS15
        {
            max_rate = (bw_40MHz) ? ((short_GI)?300:270):((short_GI)?144:130);

        }
        else if(mcs_rate&0x0080)//MCS7
        {
            max_rate = (bw_40MHz) ? ((short_GI)?150:135):((short_GI)?72:65);
        }
        else//default MCS7
        {
            //RTW_INFO("wx_get_scan, mcs_rate_bitmap=0x%x\n", mcs_rate);
            max_rate = (bw_40MHz) ? ((short_GI)?150:135):((short_GI)?72:65);
        }

        max_rate = max_rate*2;//Mbps/2;		
    }

    bss_info->tx_rate = max_rate * 500000;

    //parsing WPA/WPA2 IE
    {
        u8 wpa_ie[255],rsn_ie[255];
        u16 wpa_len=0,rsn_len=0;
        rtw_get_sec_ie(pnetwork->network.IEs ,pnetwork->network.IELength,rsn_ie,&rsn_len,wpa_ie,&wpa_len);
        //RTW_INFO("rtw_wx_get_scan: ssid=%s\n",pnetwork->network.Ssid.Ssid);
        //RTW_INFO("rtw_wx_get_scan: wpa_len=%d rsn_len=%d\n",wpa_len,rsn_len);

        if (wpa_len > 0)
        {
            bss_info->wpa_ie_len =  wpa_len;
            bss_info->wpa_proto |= WC_FLAG_ENCODE_WPA;
            wlan_get_wpa_ciphers(wpa_ie + 4, wpa_len - 2,&bss_info->wpa_group, &bss_info->wpa_pairwise);
            _rtw_memcpy(bss_info->wpa_ie,wpa_ie,wpa_len);
        }

        if (rsn_len > 0)
        {
            bss_info->rsn_ie_len =  rsn_len;
            bss_info->wpa_proto |= WC_FLAG_ENCODE_RSN;
            wlan_get_wpa_ciphers(rsn_ie + 4, rsn_len - 2,&bss_info->rsn_group, &bss_info->rsn_pairwise);
            _rtw_memcpy(bss_info->rsn_ie,rsn_ie,rsn_len);
        }
    }

    { //parsing WPS IE
        uint cnt = 0,total_ielen;	
        u8 *wpsie_ptr=NULL;
        uint wps_ielen = 0;

        u8 *ie_ptr = pnetwork->network.IEs +_FIXED_IE_LENGTH_;
        total_ielen= pnetwork->network.IELength - _FIXED_IE_LENGTH_;

        //XXX
        //Check this how manytimes its going to enter for WPS IE
        while(cnt < total_ielen) 
        {
            if(rtw_is_wps_ie(&ie_ptr[cnt], &wps_ielen) && (wps_ielen>2))			
            {
                wpsie_ptr = &ie_ptr[cnt];
                bss_info->wps_ie_len = (u16)wps_ielen;
                _rtw_memcpy(bss_info->wps_ie,wpsie_ptr,wps_ielen);
            }			
            cnt+=ie_ptr[cnt+1]+2; //goto next
        }
    }

    {
        struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
        u8 ss, sq;

        /* Add quality statistics */
        if ( check_fwstate(pmlmepriv, _FW_LINKED)== _TRUE &&
                is_same_network(&pmlmepriv->cur_network.network, &pnetwork->network, 0)) {
            ss = padapter->recvpriv.signal_strength;
            sq = padapter->recvpriv.signal_qual;
        } else {
            ss = pnetwork->network.PhyInfo.SignalStrength;
            sq = pnetwork->network.PhyInfo.SignalQuality;
        }

        bss_info->strength = translate_percentage_to_dbm(ss);
        bss_info->level = ss;//%
        bss_info->qual     = sq;
#ifdef CONFIG_BT_COEXIST
        //BT_SignalCompensation(padapter, &iwe.u.qual.level, NULL);
#endif // CONFIG_BT_COEXIST

        bss_info->noise = 156; // -100 noise level suggest by zhf@rockchips
        //RTW_INFO("iqual=%d, ilevel=%d, inoise=%d, iupdated=%d\n", iwe.u.qual.qual, iwe.u.qual.level , iwe.u.qual.noise, iwe.u.qual.updated);
    }

    return 0;	
}

void rtw_indicate_wx_assoc_event(_adapter *padapter)
{
	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;

	if(check_fwstate(pmlmepriv, WIFI_STATION_STATE) == _TRUE)
	{
		struct rtk_ConnetResult conRes;

		_rtw_memcpy(conRes.bssid, pmlmepriv->assoc_bssid, ETH_ALEN);
		conRes.connectStatus = 0;
		conRes.freq= rtw_ch2freq(pmlmepriv->cur_network.network.Configuration.DSConfig);
		conRes.statusCode=  pmlmepriv->join_status;
		conRes.reqIe = pmlmepriv->assoc_req + sizeof(struct rtw_ieee80211_hdr_3addr) + _ASOCREQ_IE_OFFSET_;
		conRes.reqIeLen = pmlmepriv->assoc_req_len-sizeof(struct rtw_ieee80211_hdr_3addr) - _ASOCREQ_IE_OFFSET_;
	
		conRes.rspIe = pmlmepriv->assoc_rsp + sizeof(struct rtw_ieee80211_hdr_3addr) + _ASOCRSP_IE_OFFSET_;
		conRes.rspIeLen = pmlmepriv->assoc_rsp_len -sizeof(struct rtw_ieee80211_hdr_3addr) - _ASOCRSP_IE_OFFSET_;
	
		RTW_INFO("assoc success\n");
		HdfWifiEventConnectResult(rtw_netdev[0]->dev,&conRes);
	}
	
	
}

void indicate_wx_scan_complete_event(_adapter *padapter)
{	
	RTW_INFO("+rtw_indicate_wx_scan_complete_event\n");
	HdfWifiEventScanDone(rtw_netdev[0]->dev, WIFI_SCAN_SUCCESS);

}

void indicate_wx_scan_get_result_event(_adapter *padapter)
{		
	struct rf_ctl_t *rfctl = adapter_to_rfctl(padapter);
	RT_CHANNEL_INFO *chset = rfctl->channel_set;
	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
	_irqL	irqL;
	_list					*plist, *phead;
	_queue				*queue	= &(pmlmepriv->scanned_queue);
	struct	wlan_network	*pnetwork = NULL;
	u8 ch;
	u32 cnt=0;
	int ret = 0;
	u8 ie_offset;
	u16 cap;
	
	if (adapter_to_pwrctl(padapter)->brfoffbyhw && rtw_is_drv_stopped(padapter)) {
		return;
    }

	_enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);

    phead = get_list_head(queue);
    plist = get_next(phead);

    cnt = 0;
    while(1)
    {
        if (rtw_end_of_queue_search(phead,plist)== _TRUE) {
            break;
        }

        pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
        ch = pnetwork->network.Configuration.DSConfig;

        //report network only if the current channel set contains the channel to which this network belongs
        if(rtw_chset_search_ch(chset, ch) >= 0
            && rtw_mlme_band_check(padapter, ch) == _TRUE
#ifdef CONFIG_VALIDATE_SSID
            && _TRUE == rtw_validate_ssid(&(pnetwork->network.Ssid))
#endif
          && (!IS_DFS_SLAVE_WITH_RD(rfctl)
              || rtw_odm_dfs_domain_unknown(rfctl_to_dvobj(rfctl))
              || !rtw_chset_is_ch_non_ocp(chset, ch))
          )
        {
			if (cnt >= SCAN_AP_LIMIT) {
				RTW_INFO("cnt value > SCAN_AP_LIMIT\n");
				break;
			}
				

			struct rtk_ScannedBssInfo bssInfo;
			struct rtk_channel_info  channel;

			channel.ChannelNum = chset[rtw_chset_search_ch(chset, ch)].ChannelNum;
			channel.flags = chset[rtw_chset_search_ch(chset, ch)].ScanType;
			channel.ChannelFreq = rtw_ch2freq(chset[rtw_chset_search_ch(chset, ch)].ChannelNum);
			
			bssInfo.signal =pnetwork->network.Rssi;
			bssInfo.freq = channel.ChannelFreq;

			bssInfo.arry[0]=pnetwork->network.Reserved[0];
			if (pnetwork->network.Reserved[0] == BSS_TYPE_BCN) {
				ie_offset = _BEACON_IE_OFFSET_;
			} else {
				if (pnetwork->network.Reserved[0] == BSS_TYPE_PROB_RSP) {
					ie_offset = _PROBERSP_IE_OFFSET_;
				} else if (pnetwork->network.Reserved[0] == BSS_TYPE_PROB_REQ) {
					ie_offset = _PROBEREQ_IE_OFFSET_;
				} else {
					ie_offset = _FIXED_IE_LENGTH_;
				}
			}


			bssInfo.mgmtLen = sizeof(struct ieee80211_mgmt) + pnetwork->network.IELength - ie_offset;

			bssInfo.mgmt= (struct ieee80211_mgmt*)_rtw_malloc(bssInfo.mgmtLen);
			_rtw_memset(bssInfo.mgmt, 0, bssInfo.mgmtLen);

			_rtw_memcpy(bssInfo.mgmt->bssid, pnetwork->network.MacAddress, ETH_ALEN);				


			bssInfo.mgmt->u.probe_resp.beacon_int = pnetwork->network.Configuration.BeaconPeriod;


			_rtw_memcpy((u8 *)&cap, rtw_get_capability_from_ie(pnetwork->network.IEs), 2);

			bssInfo.mgmt->u.probe_resp.capab_info = rtw_le16_to_cpu(cap);
			

			_rtw_memcpy(bssInfo.mgmt->u.probe_resp.variable, pnetwork->network.IEs+ie_offset, pnetwork->network.IELength-ie_offset);

			
			ret = HdfWifiEventInformBssFrame(rtw_netdev[0]->dev, &channel, &bssInfo);
			
			if(ret!=0)
			{
				RTW_INFO("%s,InformBssFrame fail ret=%d\n",__func__,ret);
			}
			rtw_mfree(bssInfo.mgmt,  bssInfo.mgmtLen);
			rtw_mdelay_os(1);
			cnt++;

        }

        plist = get_next(plist);
    }        

    _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
}

void rtw_indicate_wx_disassoc_event(_adapter *padapter, u16 reason)
{	
	RTW_INFO("indicate disassoc\n");	
	HdfWifiEventDisconnected(padapter->pnetdev->dev,reason,
		padapter->mlmepriv.cur_network.network.IEs,padapter->mlmepriv.cur_network.network.IELength);
}

static int wpa_set_encryption(struct net_device *dev, struct ieee_param *param, u32 param_len)
{
	int ret = 0;
	u32 wep_key_idx, wep_key_len,wep_total_len;
	struct net_device *netdev = rtw_get_netdev(dev);
	_adapter *padapter = (_adapter *)rtw_netdev_priv(netdev);
	struct mlme_priv 	*pmlmepriv = &padapter->mlmepriv;		
	struct security_priv *psecuritypriv = &padapter->securitypriv;
#ifdef CONFIG_P2P
	struct wifidirect_info* pwdinfo = &padapter->wdinfo;
#endif //CONFIG_P2P



	param->u.crypt.err = 0;
	param->u.crypt.alg[IEEE_CRYPT_ALG_NAME_LEN - 1] = '\0';

	if (param_len < (u32) ((u8 *) param->u.crypt.key - (u8 *) param) + param->u.crypt.key_len)
	{
		ret =  -EINVAL;
		goto exit;
	}

	if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff &&
	    param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff &&
	    param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) 
	{

		if (param->u.crypt.idx >= WEP_KEYS
#ifdef CONFIG_IEEE80211W
			&& param->u.crypt.idx > BIP_MAX_KEYID
#endif //CONFIG_IEEE80211W
			)
		{
			ret = -EINVAL;
			goto exit;
		}
	} 
	else 
	{
#ifdef CONFIG_WAPI_SUPPORT
		if (strcmp(param->u.crypt.alg, "SMS4"))
#endif
		{
			ret = -EINVAL;
			goto exit;
		}
	}

	if (strcmp(param->u.crypt.alg, "WEP") == 0)
	{
		RTW_INFO("wpa_set_encryption, crypt.alg = WEP\n");

		wep_key_idx = param->u.crypt.idx;
		wep_key_len = param->u.crypt.key_len;

		if ((wep_key_idx > WEP_KEYS) || (wep_key_len <= 0))
		{
			ret = -EINVAL;
			goto exit;
		}

		if (psecuritypriv->bWepDefaultKeyIdxSet == 0) {
			/* wep default key has not been set, so use this key index as default key.*/

			wep_key_len = wep_key_len <= 5 ? 5 : 13;

			psecuritypriv->ndisencryptstatus = Ndis802_11Encryption1Enabled;
			psecuritypriv->dot11PrivacyAlgrthm = _WEP40_;
			psecuritypriv->dot118021XGrpPrivacy = _WEP40_;

			if (wep_key_len == 13)
			{
				psecuritypriv->dot11PrivacyAlgrthm = _WEP104_;
				psecuritypriv->dot118021XGrpPrivacy = _WEP104_;
			}

			psecuritypriv->dot11PrivacyKeyIndex = wep_key_idx;
		}
			
		_rtw_memcpy(&(psecuritypriv->dot11DefKey[wep_key_idx].skey[0]), param->u.crypt.key, wep_key_len);
			
		psecuritypriv->dot11DefKeylen[wep_key_idx] = wep_key_len;

		psecuritypriv->key_mask |= BIT(wep_key_idx);

		goto exit;		
	}

	if(padapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) // 802_1x
	{
		struct sta_info * psta,*pbcmc_sta;
		struct sta_priv * pstapriv = &padapter->stapriv;

		if (check_fwstate(pmlmepriv, WIFI_STATION_STATE | WIFI_MP_STATE) == _TRUE) //sta mode
		{
			psta = rtw_get_stainfo(pstapriv, get_bssid(pmlmepriv));				
			if (psta == NULL) {
				//DEBUG_ERR( ("Set wpa_set_encryption: Obtain Sta_info fail \n"));
			}
			else
			{
				//Jeff: don't disable ieee8021x_blocked while clearing key
				if (strcmp(param->u.crypt.alg, "none") != 0) 
					psta->ieee8021x_blocked = _FALSE;
				
				if((padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption2Enabled)||
						(padapter->securitypriv.ndisencryptstatus ==  Ndis802_11Encryption3Enabled))
				{
					psta->dot118021XPrivacy = padapter->securitypriv.dot11PrivacyAlgrthm;
				}		

				if(param->u.crypt.set_tx ==1)//pairwise key
				{ 
					_rtw_memcpy(psta->dot118021x_UncstKey.skey,  param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len));
					
					if(strcmp(param->u.crypt.alg, "TKIP") == 0)//set mic key
					{						
						//DEBUG_ERR(("\nset key length :param->u.crypt.key_len=%d\n", param->u.crypt.key_len));
						_rtw_memcpy(psta->dot11tkiptxmickey.skey, &(param->u.crypt.key[16]), 8);
						_rtw_memcpy(psta->dot11tkiprxmickey.skey, &(param->u.crypt.key[24]), 8);

						padapter->securitypriv.busetkipkey=_FALSE;
						//rtw_set_timer(&padapter->securitypriv.tkip_timer, 50);						
					}

					//DEBUG_ERR((" param->u.crypt.key_len=%d\n",param->u.crypt.key_len));
					RTW_INFO(" ~~~~set sta key:unicastkey\n");
					
					rtw_setstakey_cmd(padapter, psta, UNICAST_KEY, _TRUE);
					
					psta->bpairwise_key_installed = _TRUE;
					
				}
				else//group key
				{ 					
					if(strcmp(param->u.crypt.alg, "TKIP") == 0 || strcmp(param->u.crypt.alg, "CCMP") == 0)
					{
						_rtw_memcpy(padapter->securitypriv.dot118021XGrpKey[param->u.crypt.idx].skey,  param->u.crypt.key,(param->u.crypt.key_len>16 ?16:param->u.crypt.key_len));
						//only TKIP group key need to install this
						if(param->u.crypt.key_len > 16)
						{
							_rtw_memcpy(padapter->securitypriv.dot118021XGrptxmickey[param->u.crypt.idx].skey,&(param->u.crypt.key[16]),8);
							_rtw_memcpy(padapter->securitypriv.dot118021XGrprxmickey[param->u.crypt.idx].skey,&(param->u.crypt.key[24]),8);
						}
						padapter->securitypriv.binstallGrpkey = _TRUE;	
						//DEBUG_ERR((" param->u.crypt.key_len=%d\n", param->u.crypt.key_len));
						RTW_INFO(" ~~~~set sta key:groupkey\n");
	
						padapter->securitypriv.dot118021XGrpKeyid = param->u.crypt.idx;
	
						rtw_set_key(padapter,&padapter->securitypriv,param->u.crypt.idx, 1, _TRUE);
					}
#ifdef CONFIG_IEEE80211W
					else if(strcmp(param->u.crypt.alg, "BIP") == 0)
					{
						int no;
						//printk("BIP key_len=%d , index=%d @@@@@@@@@@@@@@@@@@\n", param->u.crypt.key_len, param->u.crypt.idx);
						//save the IGTK key, length 16 bytes
						_rtw_memcpy(padapter->securitypriv.dot11wBIPKey[param->u.crypt.idx].skey,  param->u.crypt.key,(param->u.crypt.key_len>16 ?16:param->u.crypt.key_len));
						/*printk("IGTK key below:\n");
						for(no=0;no<16;no++)
							printk(" %02x ", padapter->securitypriv.dot11wBIPKey[param->u.crypt.idx].skey[no]);
						printk("\n");*/
						padapter->securitypriv.dot11wBIPKeyid = param->u.crypt.idx;
						padapter->securitypriv.binstallBIPkey = _TRUE;
						RTW_INFO(" ~~~~set sta key:IGKT\n");
					}
#endif //CONFIG_IEEE80211W
					
#ifdef CONFIG_P2P
					if(rtw_p2p_chk_state(pwdinfo, P2P_STATE_PROVISIONING_ING))
					{
						rtw_p2p_set_state(pwdinfo, P2P_STATE_PROVISIONING_DONE);
					}
#endif //CONFIG_P2P
					
				}						
			}

			pbcmc_sta=rtw_get_bcmc_stainfo(padapter);
			if(pbcmc_sta==NULL)
			{
				//DEBUG_ERR( ("Set OID_802_11_ADD_KEY: bcmc stainfo is null \n"));
			}
			else
			{
				//Jeff: don't disable ieee8021x_blocked while clearing key
				if (strcmp(param->u.crypt.alg, "none") != 0) 
					pbcmc_sta->ieee8021x_blocked = _FALSE;
				
				if((padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption2Enabled)||
						(padapter->securitypriv.ndisencryptstatus ==  Ndis802_11Encryption3Enabled))
				{							
					pbcmc_sta->dot118021XPrivacy = padapter->securitypriv.dot11PrivacyAlgrthm;
				}					
			}				
		}
		else if(check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) //adhoc mode
		{		
		}			
	}

#ifdef CONFIG_WAPI_SUPPORT
	if (strcmp(param->u.crypt.alg, "SMS4") == 0)
	{
		PRT_WAPI_T			pWapiInfo = &padapter->wapiInfo;
		PRT_WAPI_STA_INFO	pWapiSta;
		u8					WapiASUEPNInitialValueSrc[16] = {0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C} ;
		u8					WapiAEPNInitialValueSrc[16] = {0x37,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C} ;
		u8 					WapiAEMultiCastPNInitialValueSrc[16] = {0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C,0x36,0x5C} ;

		if(param->u.crypt.set_tx == 1)
		{
			list_for_each_entry(pWapiSta, &pWapiInfo->wapiSTAUsedList, list) {
				if(_rtw_memcmp(pWapiSta->PeerMacAddr,param->sta_addr,6))
				{
					_rtw_memcpy(pWapiSta->lastTxUnicastPN,WapiASUEPNInitialValueSrc,16);

					pWapiSta->wapiUsk.bSet = true;
					_rtw_memcpy(pWapiSta->wapiUsk.dataKey,param->u.crypt.key,16);
					_rtw_memcpy(pWapiSta->wapiUsk.micKey,param->u.crypt.key+16,16);
					pWapiSta->wapiUsk.keyId = param->u.crypt.idx ;
					pWapiSta->wapiUsk.bTxEnable = true;

					_rtw_memcpy(pWapiSta->lastRxUnicastPNBEQueue,WapiAEPNInitialValueSrc,16);
					_rtw_memcpy(pWapiSta->lastRxUnicastPNBKQueue,WapiAEPNInitialValueSrc,16);
					_rtw_memcpy(pWapiSta->lastRxUnicastPNVIQueue,WapiAEPNInitialValueSrc,16);
					_rtw_memcpy(pWapiSta->lastRxUnicastPNVOQueue,WapiAEPNInitialValueSrc,16);
					_rtw_memcpy(pWapiSta->lastRxUnicastPN,WapiAEPNInitialValueSrc,16);
					pWapiSta->wapiUskUpdate.bTxEnable = false;
					pWapiSta->wapiUskUpdate.bSet = false;

					if (psecuritypriv->sw_encrypt== false || psecuritypriv->sw_decrypt == false)
					{
						//set unicast key for ASUE
						rtw_wapi_set_key(padapter, &pWapiSta->wapiUsk, pWapiSta, false, false);
					}
				}
			}
		}
		else
		{
			list_for_each_entry(pWapiSta, &pWapiInfo->wapiSTAUsedList, list) {
				if(_rtw_memcmp(pWapiSta->PeerMacAddr,get_bssid(pmlmepriv),6))
				{
					pWapiSta->wapiMsk.bSet = true;
					_rtw_memcpy(pWapiSta->wapiMsk.dataKey,param->u.crypt.key,16);
					_rtw_memcpy(pWapiSta->wapiMsk.micKey,param->u.crypt.key+16,16);
					pWapiSta->wapiMsk.keyId = param->u.crypt.idx ;
					pWapiSta->wapiMsk.bTxEnable = false;
					if(!pWapiSta->bSetkeyOk)
						pWapiSta->bSetkeyOk = true;
					pWapiSta->bAuthenticateInProgress = false;

					_rtw_memcpy(pWapiSta->lastRxMulticastPN, WapiAEMultiCastPNInitialValueSrc, 16);

					if (psecuritypriv->sw_decrypt == false)
					{
						//set rx broadcast key for ASUE
						rtw_wapi_set_key(padapter, &pWapiSta->wapiMsk, pWapiSta, true, false);
					}
				}

			}
		}
	}
#endif

exit:
	

	RTW_INFO("%s,ret=%d\n",__func__,ret);
	return ret;	
}

static int rtw_set_wpa_ie(_adapter *padapter, char *pie, unsigned short ielen)
{
	u8 *buf=NULL, *pos=NULL;	
	u32 left; 	
	int group_cipher = 0, pairwise_cipher = 0;
	int ret = 0;
	u8 null_addr[]= {0,0,0,0,0,0};
#ifdef CONFIG_P2P
	struct wifidirect_info* pwdinfo = &padapter->wdinfo;
#endif //CONFIG_P2P

	if((ielen > MAX_WPA_IE_LEN) || (pie == NULL)){
		_clr_fwstate_(&padapter->mlmepriv, WIFI_UNDER_WPS);
		if(pie == NULL)	
			return ret;
		else
			return -EINVAL;
	}

	if(ielen)
	{		
		buf = rtw_zmalloc(ielen);
		if (buf == NULL){
			ret =  -ENOMEM;
			goto exit;
		}
	
		_rtw_memcpy(buf, pie , ielen);

		//dump
		{
			int i;
			RTW_INFO("\n wpa_ie(length:%d):\n", ielen);
			for(i=0;i<ielen;i=i+8)
				RTW_INFO("0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x \n",buf[i],buf[i+1],buf[i+2],buf[i+3],buf[i+4],buf[i+5],buf[i+6],buf[i+7]);
		}
	
		pos = buf;
		if(ielen < RSN_HEADER_LEN){
			RTW_INFO("Ie len too short %d\n", ielen);
			ret  = -1;
			goto exit;
		}

#if 0
		pos += RSN_HEADER_LEN;
		left  = ielen - RSN_HEADER_LEN;
		
		if (left >= RSN_SELECTOR_LEN){
			pos += RSN_SELECTOR_LEN;
			left -= RSN_SELECTOR_LEN;
		}		
		else if (left > 0){
			RTW_INFO("Ie length mismatch, %u too much \n", left);
			ret =-1;
			goto exit;
		}
#endif		
		
		if(rtw_parse_wpa_ie(buf, ielen, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS)
		{
			padapter->securitypriv.dot11AuthAlgrthm= dot11AuthAlgrthm_8021X;
			padapter->securitypriv.ndisauthtype=Ndis802_11AuthModeWPAPSK;
			_rtw_memcpy(padapter->securitypriv.supplicant_ie, &buf[0], ielen);	
		}
	
		if(rtw_parse_wpa2_ie(buf, ielen, &group_cipher, &pairwise_cipher, NULL, NULL) == _SUCCESS)
		{
			padapter->securitypriv.dot11AuthAlgrthm= dot11AuthAlgrthm_8021X;
			padapter->securitypriv.ndisauthtype=Ndis802_11AuthModeWPA2PSK;	
			_rtw_memcpy(padapter->securitypriv.supplicant_ie, &buf[0], ielen);	
		}
			
		if (group_cipher == 0)
		{
			group_cipher = WPA_CIPHER_NONE;
		}
		if (pairwise_cipher == 0)
		{
			pairwise_cipher = WPA_CIPHER_NONE;
		}
			
		switch(group_cipher)
		{
			case WPA_CIPHER_NONE:
				padapter->securitypriv.dot118021XGrpPrivacy=_NO_PRIVACY_;
				padapter->securitypriv.ndisencryptstatus=Ndis802_11EncryptionDisabled;
				break;
			case WPA_CIPHER_WEP40:
				padapter->securitypriv.dot118021XGrpPrivacy=_WEP40_;
				padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;
				break;
			case WPA_CIPHER_TKIP:
				padapter->securitypriv.dot118021XGrpPrivacy=_TKIP_;
				padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption2Enabled;
				break;
			case WPA_CIPHER_CCMP:
				padapter->securitypriv.dot118021XGrpPrivacy=_AES_;
				padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption3Enabled;
				break;
			case WPA_CIPHER_WEP104:	
				padapter->securitypriv.dot118021XGrpPrivacy=_WEP104_;
				padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;
				break;
		}

		switch(pairwise_cipher)
		{
			case WPA_CIPHER_NONE:
				padapter->securitypriv.dot11PrivacyAlgrthm=_NO_PRIVACY_;
				padapter->securitypriv.ndisencryptstatus=Ndis802_11EncryptionDisabled;
				break;
			case WPA_CIPHER_WEP40:
				padapter->securitypriv.dot11PrivacyAlgrthm=_WEP40_;
				padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;
				break;
			case WPA_CIPHER_TKIP:
				padapter->securitypriv.dot11PrivacyAlgrthm=_TKIP_;
				padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption2Enabled;
				break;
			case WPA_CIPHER_CCMP:
				padapter->securitypriv.dot11PrivacyAlgrthm=_AES_;
				padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption3Enabled;
				break;
			case WPA_CIPHER_WEP104:	
				padapter->securitypriv.dot11PrivacyAlgrthm=_WEP104_;
				padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;
				break;
		}
		
		_clr_fwstate_(&padapter->mlmepriv, WIFI_UNDER_WPS);
		{//set wps_ie	
			u16 cnt = 0;	
			u8 eid, wps_oui[4]={0x0,0x50,0xf2,0x04};
			 
			while( cnt < ielen )
			{
				eid = buf[cnt];
		
				if((eid==_VENDOR_SPECIFIC_IE_)&&(_rtw_memcmp(&buf[cnt+2], wps_oui, 4)==_TRUE))
				{
					RTW_INFO("SET WPS_IE\n");

					padapter->securitypriv.wps_ie_len = ((buf[cnt+1]+2) < MAX_WPS_IE_LEN) ? (buf[cnt+1]+2):MAX_WPS_IE_LEN;

					_rtw_memcpy(padapter->securitypriv.wps_ie, &buf[cnt], padapter->securitypriv.wps_ie_len);
					
					set_fwstate(&padapter->mlmepriv, WIFI_UNDER_WPS);
					
#ifdef CONFIG_P2P
					if(rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_OK))
					{
						rtw_p2p_set_state(pwdinfo, P2P_STATE_PROVISIONING_ING);
					}
#endif //CONFIG_P2P
					cnt += buf[cnt+1]+2;
					
					break;
				} else {
					cnt += buf[cnt+1]+2; //goto next	
				}				
			}			
		}		
	}
	
	//TKIP and AES disallow multicast packets until installing group key
        if(padapter->securitypriv.dot11PrivacyAlgrthm == _TKIP_
                || padapter->securitypriv.dot11PrivacyAlgrthm == _TKIP_WTMIC_
                || padapter->securitypriv.dot11PrivacyAlgrthm == _AES_)
                //WPS open need to enable multicast
                //|| check_fwstate(&padapter->mlmepriv, WIFI_UNDER_WPS) == _TRUE)
                rtw_hal_set_hwreg(padapter, HW_VAR_OFF_RCR_AM, null_addr);
	
	RTW_INFO("rtw_set_wpa_ie: pairwise_cipher=0x%08x padapter->securitypriv.ndisencryptstatus=%d padapter->securitypriv.ndisauthtype=%d\n",
		  pairwise_cipher, padapter->securitypriv.ndisencryptstatus, padapter->securitypriv.ndisauthtype);
 	
exit:

	if (buf) rtw_mfree(buf, ielen);

	return ret;
}

static int wpa_set_auth_algs(struct net_device *dev, u32 value)
{	
	struct net_device *netdev = rtw_get_netdev(dev);
	_adapter *padapter = (_adapter *)rtw_netdev_priv(netdev);
	int ret = 0;

	if ((value & AUTH_ALG_SHARED_KEY)&&(value & AUTH_ALG_OPEN_SYSTEM))
	{
		RTW_INFO("wpa_set_auth_algs, AUTH_ALG_SHARED_KEY and  AUTH_ALG_OPEN_SYSTEM [value:0x%x]\n",value);
		padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;
		padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeAutoSwitch;
		padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Auto;
	} 
	else if (value & AUTH_ALG_SHARED_KEY)
	{
		RTW_INFO("wpa_set_auth_algs, AUTH_ALG_SHARED_KEY  [value:0x%x]\n",value);
		padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;

#ifdef CONFIG_PLATFORM_MT53XX
		padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeAutoSwitch;
		padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Auto;
#else
		padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeShared;
		padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Shared;
#endif
	} 
	else if(value & AUTH_ALG_OPEN_SYSTEM)
	{
		RTW_INFO("wpa_set_auth_algs, AUTH_ALG_OPEN_SYSTEM\n");
		//padapter->securitypriv.ndisencryptstatus = Ndis802_11EncryptionDisabled;
		if(padapter->securitypriv.ndisauthtype < Ndis802_11AuthModeWPAPSK)
		{
#ifdef CONFIG_PLATFORM_MT53XX
			padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeAutoSwitch;
			padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Auto;
#else
			padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeOpen;
 			padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Open;
#endif
		}
		
	}
	else if(value & AUTH_ALG_LEAP)
	{
		RTW_INFO("wpa_set_auth_algs, AUTH_ALG_LEAP\n");
	}
	else
	{
		RTW_INFO("wpa_set_auth_algs, error!\n");
		ret = -EINVAL;
	}

	return ret;
	
}

/*static int hex2num_i(char c)
{
	if (c >= '0' && c <= '9')
		return c - '0';
	if (c >= 'a' && c <= 'f')
		return c - 'a' + 10;
	if (c >= 'A' && c <= 'F')
		return c - 'A' + 10;
	return -1;
}*/

/**
 * hwaddr_aton - Convert ASCII string to MAC address
 * @txt: MAC address as a string (e.g., "00:11:22:33:44:55")
 * @addr: Buffer for the MAC address (ETH_ALEN = 6 bytes)
 * Returns: 0 on success, -1 on failure (e.g., string not a MAC address)
 */
static int hwaddr_aton_i(const char *txt, u8 *addr)
{
	int i;

	for (i = 0; i < 6; i++) {
		int a, b;

		a = hex2num_i(*txt++);
		if (a < 0)
			return -1;
		b = hex2num_i(*txt++);
		if (b < 0)
			return -1;
		*addr++ = (a << 4) | b;
		if (i < 5 && *txt++ != ':')
			return -1;
	}

	return 0;
}


/****************************************************************************/


static int rtw_wx_set_freq(struct net_device *dev, struct rtw_wc_param *iwcp) 
{	

	struct net_device *netdev = rtw_get_netdev(dev);
	_adapter *padapter = (_adapter *)rtw_netdev_priv(netdev);
	struct	mlme_priv	*pmlmepriv = &(padapter->mlmepriv);
	struct wlan_network  *cur_network = &(pmlmepriv->cur_network);
	int exp = 1, freq = 0, div = 0;

	

	RTW_INFO("+rtw_wx_set_freq\n");

	freq = iwcp->param1;

	/* If freq is invalid, rtw_freq2ch() will return channel 1 */
	if (check_fwstate(pmlmepriv, WIFI_AP_STATE))
		padapter->mlmeextpriv.cur_channel = freq;
	else
		padapter->mlmeextpriv.cur_channel = rtw_freq2ch(freq);
	
	RTW_INFO("%s: set to channel %d\n", __func__, padapter->mlmeextpriv.cur_channel);

	set_channel_bwmode(padapter, padapter->mlmeextpriv.cur_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, CHANNEL_WIDTH_20);

	
	
	return 0;
}

static int rtw_wx_get_freq(struct net_device *dev, struct rtw_wc_param *iwcp) 
{
	struct net_device *netdev = rtw_get_netdev(dev);
	_adapter *padapter = (_adapter *)rtw_netdev_priv(netdev);
	struct	mlme_priv	*pmlmepriv = &(padapter->mlmepriv);
	WLAN_BSSID_EX  *pcur_bss = &pmlmepriv->cur_network.network;
	
	if(check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE)
	{
		//wrqu->freq.m = ieee80211_wlan_frequencies[pcur_bss->Configuration.DSConfig-1] * 100000;
		//wrqu->freq.m = rtw_ch2freq(pcur_bss->Configuration.DSConfig) * 100000;
		//wrqu->freq.e = 1;
		//wrqu->freq.i = pcur_bss->Configuration.DSConfig;
        iwcp->param1 =  pcur_bss->Configuration.DSConfig;

	}
	else{
		//wrqu->freq.m = rtw_ch2freq(padapter->mlmeextpriv.cur_channel) * 100000;
		//wrqu->freq.e = 1;
		//wrqu->freq.i = padapter->mlmeextpriv.cur_channel;
        iwcp->param1 =  padapter->mlmeextpriv.cur_channel; 
	}

	return 0;
}

static int rtw_wx_channel_list(struct net_device *dev, struct rtw_wc_param *iwcp) 
{
	struct net_device *netdev = rtw_netdev[0];
	_adapter *padapter = (_adapter *)rtw_netdev_priv(netdev);	
	struct rf_ctl_t *rfctl = adapter_to_rfctl(padapter);
	u8 ChannelPlan;
	int is_5g;
	u8	chanset_size = 0;
	struct rtk_channel_info *channel_set = (struct rtk_channel_info*)(iwcp->wc_apps_data);

	ChannelPlan=rfctl->ChannelPlan;
	is_5g=iwcp->param1;

	chanset_size = rtw_get_chnlPlan(padapter, ChannelPlan, is_5g, channel_set);

	iwcp->param2 = chanset_size;
	return 0;
}

static int rtw_wx_set_mode(struct net_device *dev, struct rtw_wc_param *iwcp)
{
	struct net_device *netdev = rtw_netdev[0];
	_adapter *padapter = (_adapter *)rtw_netdev_priv(netdev);
	PHAL_DATA_TYPE	pHalData = GET_HAL_DATA(padapter);
	NDIS_802_11_NETWORK_INFRASTRUCTURE networkType ;
	int ret = 0;
	
	RTW_INFO("Enter rtw_wx_set_mode \n");

	if(_FAIL == rtw_pwr_wakeup(padapter)) {
		ret= -EPERM;
		goto exit;
	}

	if (rtw_get_hw_init_completed(padapter)==_FALSE){
		ret = -EPERM;
		goto exit;
	}

	switch(iwcp->param1)
	{
		case WC_FLAG_MODE_AUTO:
			networkType = Ndis802_11AutoUnknown;
			RTW_INFO("set_mode = WC_MODE_AUTO \n");
			break;				
		case WC_FLAG_MODE_ADHOC:		
			networkType = Ndis802_11IBSS;
			RTW_INFO("set_mode = WC_MODE_IBSS \n");
			break;
		case WC_FLAG_MODE_MASTER:		
			networkType = (NDIS_802_11_NETWORK_INFRASTRUCTURE)Ndis802_11APMode;
			RTW_INFO("set_mode = WC_MODE_MASTER \n");
			//rtw_setopmode_cmd(padapter, networkType);	
			break;				
		case WC_FLAG_MODE_INFRA:
			networkType = Ndis802_11Infrastructure;
			RTW_INFO("set_mode = WC_MODE_INFRA \n");
			break;
		case WC_FLAG_MODE_MONITOR:
			networkType = Ndis802_11Monitor;
			RTW_INFO("set_mode = WC_FLAG_MODE_MONITOR \n");
			break;	
	
		default :
			ret = -EINVAL;;
			RTW_INFO("\n Mode: %d is not supported  \n", iwcp->param1);
			goto exit;
	}
	
/*	
	if(Ndis802_11APMode == networkType)
	{
		rtw_setopmode_cmd(padapter, networkType);
	}	
	else
	{
		rtw_setopmode_cmd(padapter, Ndis802_11AutoUnknown);	
	}
*/
	
	if (rtw_set_802_11_infrastructure_mode(padapter, networkType, 0) ==_FALSE){

		ret = -EPERM;
		goto exit;

	}

	rtw_setopmode_cmd(padapter, networkType, _TRUE);
exit:
	
	
	
	return ret;
	
}

static int rtw_wx_get_mode(struct net_device *dev, struct rtw_wc_param *iwcp)
{
	struct net_device *netdev = rtw_get_netdev(dev);
	_adapter *padapter = (_adapter *)rtw_netdev_priv(netdev);
	struct	mlme_priv	*pmlmepriv = &(padapter->mlmepriv);
	
	RTW_INFO(" rtw_wx_get_mode \n");

	

	if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == _TRUE)
	{
		iwcp->param1 = WC_FLAG_MODE_INFRA;
	}
	else if  ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == _TRUE) ||
		       (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == _TRUE))
		
	{
		iwcp->param1 = WC_FLAG_MODE_ADHOC;
	}
	else if(check_fwstate(pmlmepriv, WIFI_AP_STATE) == _TRUE)
	{
		iwcp->param1 = WC_FLAG_MODE_MASTER;
	}
	else
	{
		iwcp->param1 = WC_FLAG_MODE_AUTO;
	}

	
	
	return 0;
	
}


static int rtw_wx_set_pmkid(struct net_device *dev, struct rtw_wc_param *iwcp)
{
    struct net_device *netdev = rtw_get_netdev(dev);
	_adapter *padapter = (_adapter *)rtw_netdev_priv(netdev);
    u8          j,blInserted = _FALSE;
    int         intReturn = _FALSE;
    struct mlme_priv  *pmlmepriv = &padapter->mlmepriv;
    struct security_priv *psecuritypriv = &padapter->securitypriv;
    struct rtw_wc_pmksa*  pPMK = ( struct rtw_wc_pmksa* ) iwcp->wc_apps_data;
    u8     strZeroMacAddress[ ETH_ALEN ] = { 0x00 };
    u8     strIssueBssid[ ETH_ALEN ] = { 0x00 };

    if (pmlmepriv);

    /*
       struct iw_pmksa
       {
       __u32   cmd;
       struct sockaddr bssid;
       __u8    pmkid[IW_PMKID_LEN];   //IW_PMKID_LEN=16
       }
       There are the BSSID information in the bssid.sa_data array.
       If cmd is IW_PMKSA_FLUSH, it means the wpa_suppplicant wants to clear all the PMKID information.
       If cmd is IW_PMKSA_ADD, it means the wpa_supplicant wants to add a PMKID/BSSID to driver.
       If cmd is IW_PMKSA_REMOVE, it means the wpa_supplicant wants to remove a PMKID/BSSID from driver.
       */

    _rtw_memcpy( strIssueBssid, pPMK->bssid, ETH_ALEN);
    if ( pPMK->cmd == WC_PMKSA_ADD )
    {
        RTW_INFO( "[rtw_wx_set_pmkid] IW_PMKSA_ADD!\n" );
        if ( _rtw_memcmp( strIssueBssid, strZeroMacAddress, ETH_ALEN ) == _TRUE )
        {
            return( intReturn );
        }
        else
        {
            intReturn = _TRUE;
        }
        blInserted = _FALSE;

        //overwrite PMKID
        for(j=0 ; j<NUM_PMKID_CACHE; j++)
        {
            if( _rtw_memcmp( psecuritypriv->PMKIDList[j].Bssid, strIssueBssid, ETH_ALEN) ==_TRUE )
            { // BSSID is matched, the same AP => rewrite with new PMKID.

                RTW_INFO( "[rtw_wx_set_pmkid] BSSID exists in the PMKList.\n" );

                _rtw_memcpy( psecuritypriv->PMKIDList[j].PMKID, pPMK->pmkid, WC_PMKID_LEN);
                psecuritypriv->PMKIDList[ j ].bUsed = _TRUE;
                psecuritypriv->PMKIDIndex = j+1;
                blInserted = _TRUE;
                break;
            }	
        }

        if(!blInserted)
        {
            // Find a new entry
            RTW_INFO( "[rtw_wx_set_pmkid] Use the new entry index = %d for this PMKID.\n",
                    psecuritypriv->PMKIDIndex );

            _rtw_memcpy(psecuritypriv->PMKIDList[psecuritypriv->PMKIDIndex].Bssid, strIssueBssid, ETH_ALEN);
            _rtw_memcpy(psecuritypriv->PMKIDList[psecuritypriv->PMKIDIndex].PMKID, pPMK->pmkid, WC_PMKID_LEN);

            psecuritypriv->PMKIDList[ psecuritypriv->PMKIDIndex ].bUsed = _TRUE;
            psecuritypriv->PMKIDIndex++ ;
            if(psecuritypriv->PMKIDIndex==16)
            {
                psecuritypriv->PMKIDIndex =0;
            }
        }
    }
    else if ( pPMK->cmd == WC_PMKSA_REMOVE )
    {
        RTW_INFO( "[rtw_wx_set_pmkid] IW_PMKSA_REMOVE!\n" );
        intReturn = _TRUE;
        for(j=0 ; j<NUM_PMKID_CACHE; j++)
        {
            if( _rtw_memcmp( psecuritypriv->PMKIDList[j].Bssid, strIssueBssid, ETH_ALEN) ==_TRUE )
            { // BSSID is matched, the same AP => Remove this PMKID information and reset it. 
                _rtw_memset( psecuritypriv->PMKIDList[ j ].Bssid, 0x00, ETH_ALEN );
                psecuritypriv->PMKIDList[ j ].bUsed = _FALSE;
                break;
            }	
        }
    }
    else if ( pPMK->cmd == WC_PMKSA_FLUSH ) 
    {
        RTW_INFO( "[rtw_wx_set_pmkid] IW_PMKSA_FLUSH!\n" );
        _rtw_memset( &psecuritypriv->PMKIDList[ 0 ], 0x00, sizeof( RT_PMKID_LIST ) * NUM_PMKID_CACHE );
        psecuritypriv->PMKIDIndex = 0;
        intReturn = _TRUE;
    }
    return( intReturn );
}

static int rtw_wx_get_sens(struct net_device *dev, struct rtw_wc_param *iwcp) 
{
    iwcp->param1= 0;
    return 0;
}

static int rtw_wx_get_range(struct net_device *dev, struct rtw_wc_param *iwcp) 
{
	dprintf("Enter rtw_wx_get_range \n");
}

//set bssid flow
//s1. rtw_set_802_11_infrastructure_mode()
//s2. rtw_set_802_11_authentication_mode()
//s3. set_802_11_encryption_mode()
//s4. rtw_set_802_11_bssid()
static int rtw_wx_set_wap(struct net_device *dev, struct rtw_wc_param *iwcp)
{
    _irqL	irqL;
    int ret = 0;
    struct net_device *netdev = rtw_get_netdev(dev);
	_adapter *padapter = (_adapter *)rtw_netdev_priv(netdev);
    char *temp = iwcp->wc_apps_data; //memcpy the bssid
    struct	mlme_priv	*pmlmepriv = &(padapter->mlmepriv);
    _list	*phead;
    u8 *dst_bssid, *src_bssid;
    _queue	*queue	= &(pmlmepriv->scanned_queue);
    struct	wlan_network	*pnetwork = NULL;
    NDIS_802_11_AUTHENTICATION_MODE	authmode;

    

#if 0
#ifdef CONFIG_CONCURRENT_MODE
    if(padapter->iface_type > PRIMARY_IFACE)
    {
        ret = -EINVAL;
        goto exit;
    }
#endif	
#endif

#ifdef CONFIG_CONCURRENT_MODE
    if (check_buddy_fwstate(padapter, _FW_UNDER_SURVEY|_FW_UNDER_LINKING) == _TRUE)
    {
        RTW_INFO("set bssid, but buddy_intf is under scanning or linking\n");

        ret = -EINVAL;

        goto exit;
    }
#endif

#ifdef CONFIG_DUALMAC_CONCURRENT
    if (dc_check_fwstate(padapter, _FW_UNDER_SURVEY|_FW_UNDER_LINKING)== _TRUE)
    {
        RTW_INFO("set bssid, but buddy_intf is under scanning or linking\n");
        ret = -EINVAL;
        goto exit;
    }
#endif

    if(_FAIL == rtw_pwr_wakeup(padapter))
    {
        ret= -1;
        goto exit;
    }

    if(!padapter->bup){
        ret = -1;
        goto exit;
    }

#if 0 //Raj
    if (temp->sa_family != ARPHRD_ETHER){
        ret = -EINVAL;
        goto exit;
    }
#endif

    authmode = (NDIS_802_11_AUTHENTICATION_MODE)padapter->securitypriv.ndisauthtype;
    _enter_critical_bh(&queue->lock, &irqL);
    phead = get_list_head(queue);
    pmlmepriv->pscanned = get_next(phead);

    while (1)
    {

        if ((rtw_end_of_queue_search(phead, pmlmepriv->pscanned)) == _TRUE)
        {
#if 0		
            ret = -EINVAL;
            goto exit;

            if(check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == _TRUE)
            {
                rtw_set_802_11_bssid(padapter, temp->sa_data);
                goto exit;                    
            }
            else
            {
                ret = -EINVAL;
                goto exit;
            }
#endif

            break;
        }

        pnetwork = LIST_CONTAINOR(pmlmepriv->pscanned, struct wlan_network, list);

        pmlmepriv->pscanned = get_next(pmlmepriv->pscanned);

        dst_bssid = pnetwork->network.MacAddress;

        src_bssid = (u8*)temp; //->sa_data;

        if ((_rtw_memcmp(dst_bssid, src_bssid, ETH_ALEN)) == _TRUE)
        {			
            if(!rtw_set_802_11_infrastructure_mode(padapter, pnetwork->network.InfrastructureMode, 0))
            {
                ret = -1;
                _exit_critical_bh(&queue->lock, &irqL);
                goto exit;
            }

            break;			
        }

    }		
    _exit_critical_bh(&queue->lock, &irqL);

    rtw_set_802_11_authentication_mode(padapter, authmode);
    //set_802_11_encryption_mode(padapter, padapter->securitypriv.ndisencryptstatus);
    if (rtw_set_802_11_bssid(padapter, (u8*)temp) == _FALSE) {
        ret = -1;
        goto exit;		
    }	

exit:

    

    return ret;	
}

static int rtw_wx_get_wap(struct net_device *dev, struct rtw_wc_param *iwcp) 
{

    struct net_device *netdev = rtw_get_netdev(dev);
	_adapter *padapter = (_adapter *)rtw_netdev_priv(netdev);
    struct	mlme_priv	*pmlmepriv = &(padapter->mlmepriv);
    WLAN_BSSID_EX  *pcur_bss = &pmlmepriv->cur_network.network;	

    //	_rtw_memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN);

    RTW_INFO("rtw_wx_get_wap\n");

    if  ( ((check_fwstate(pmlmepriv, _FW_LINKED)) == _TRUE) || 
            ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) == _TRUE) ||
            ((check_fwstate(pmlmepriv, WIFI_AP_STATE)) == _TRUE) )
    {

        _rtw_memcpy(iwcp->wc_apps_data, pcur_bss->MacAddress, ETH_ALEN);
    }
    else
    {
        _rtw_memset(iwcp->wc_apps_data, 0, ETH_ALEN);
    }		

    return 0;

}

static int rtw_wx_set_mlme(struct net_device *dev, struct rtw_wc_param *iwcp) 
{
#if 0
/* SIOCSIWMLME data */
struct	iw_mlme
{
	__u16		cmd; /* IW_MLME_* */
	__u16		reason_code;
	struct sockaddr	addr;
};
#endif

	int ret=0;
	u16 reason = iwcp->param1;
    u16 cmd    = iwcp->param2;
	struct net_device *netdev = rtw_get_netdev(dev);
	_adapter *padapter = (_adapter *)rtw_netdev_priv(netdev);


	RTW_INFO("%s\n", __FUNCTION__);

	RTW_INFO("%s, cmd=%d, reason=%d\n", __FUNCTION__, cmd, reason);
	
	switch (cmd) 
	{
		case WC_MLME_DEAUTH:
				if(!rtw_set_802_11_disassociate(padapter))
				ret = -1;
				break;

		case WC_MLME_DISASSOC:
				if(!rtw_set_802_11_disassociate(padapter))
						ret = -1;
				break;

		default:
			return -1;
	}

	return ret;
}

static int rtw_wx_set_scan(void *dev, struct rtw_wc_param *iwcp)
{
	u8 _status = _FALSE;
	int ret = 0;	
	struct net_device *netdev = rtw_netdev[0];
	_adapter *padapter = (_adapter *)rtw_netdev_priv(netdev);
	PHAL_DATA_TYPE	pHalData = GET_HAL_DATA(padapter);
	struct mlme_priv *pmlmepriv= &padapter->mlmepriv;
	NDIS_802_11_SSID ssid[RTW_SSID_SCAN_AMOUNT];
    struct sitesurvey_parm parm;
	_irqL	irqL;
	struct rtw_scan_req * scan_req = (struct rtw_scan_req*)(iwcp->wc_apps_data);
#ifdef CONFIG_P2P
	struct wifidirect_info *pwdinfo= &(padapter->wdinfo);	
#endif //CONFIG_P2P
	RTW_INFO("rtw_wx_set_scan\n");
    RTW_INFO("DBG_IOCTL enter %s:%d\n",__FUNCTION__, __LINE__);

    if (irqL);

#ifdef DBG_IOCTL
    RTW_INFO("DBG_IOCTL %s:%d\n",__FUNCTION__, __LINE__);
#endif

/*
#ifdef CONFIG_CONCURRENT_MODE
	if(padapter->iface_type > PRIMARY_IFACE)
	{
		ret = -1;
		goto exit;
	}
#endif
*/	

#ifdef CONFIG_MP_INCLUDED
    if (padapter->registrypriv.mp_mode == 1)
    {	
        if (check_fwstate(pmlmepriv, WIFI_MP_STATE) == _TRUE)
        {
            ret = -1;
            goto exit;
        }
    }
#endif
    if(_FAIL == rtw_pwr_wakeup(padapter))
    {
        ret= -1;
        goto exit;
    }

    /*if(padapter->bDriverStopped){
        RTW_INFO("bDriverStopped=%d\n", padapter->bDriverStopped);
        ret= -1;
		goto exit;
    }*/
	
	if(!padapter->bup){
		ret = -1;
		goto exit;
	}
	
	if (pHalData->hw_init_completed==_FALSE){
		ret = -1;
		goto exit;
	}

	// When Busy Traffic, driver do not site survey. So driver return success.
	// wpa_supplicant will not issue SIOCSIWSCAN cmd again after scan timeout.
	// modify by thomas 2011-02-22.
	if (pmlmepriv->LinkDetectInfo.bBusyTraffic == _TRUE)
	{
		indicate_wx_scan_complete_event(padapter);
		goto exit;
	} 

	if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY|_FW_UNDER_LINKING) == _TRUE)
	{
		indicate_wx_scan_complete_event(padapter);
		goto exit;
	} 

#ifdef CONFIG_BT_COEXIST
	{
		u32 curr_time, delta_time;

		// under DHCP(Special packet)
		curr_time = rtw_get_current_time();
		delta_time = curr_time - padapter->pwrctrlpriv.DelayLPSLastTimeStamp;
		delta_time = rtw_systime_to_ms(delta_time);
		if (delta_time < 500) // 500ms
		{
			RTW_INFO("%s: send DHCP pkt before %d ms, Skip scan\n", __FUNCTION__, delta_time);
			ret = -1;
			goto exit;
		}
	}
#endif

#ifdef CONFIG_CONCURRENT_MODE
	if (check_buddy_fwstate(padapter,
		_FW_UNDER_SURVEY|_FW_UNDER_LINKING|WIFI_UNDER_WPS) == _TRUE)
	{		
		if(check_buddy_fwstate(padapter, _FW_UNDER_SURVEY))
		{
			RTW_INFO("scanning_via_buddy_intf\n");
			pmlmepriv->scanning_via_buddy_intf = _TRUE;
		}		

		indicate_wx_scan_complete_event(padapter);
		
		goto exit;
	}
#endif

#ifdef CONFIG_DUALMAC_CONCURRENT
	if (dc_check_fwstate(padapter, _FW_UNDER_SURVEY|_FW_UNDER_LINKING)== _TRUE)
	{
		indicate_wx_scan_complete_event(padapter);
		goto exit;
	}
#endif

//	Mareded by Albert 20101103
//	For the DMP WiFi Display project, the driver won't to scan because
//	the pmlmepriv->scan_interval is always equal to 3.
//	So, the wpa_supplicant won't find out the WPS SoftAP.

/*
	if(pmlmepriv->scan_interval>10)
		pmlmepriv->scan_interval = 0;

	if(pmlmepriv->scan_interval > 0)
	{
		RTW_INFO("scan done\n");
		ret = 0;
		goto exit;
	}
		
*/

#ifdef CONFIG_P2P
	if ( pwdinfo->p2p_state != P2P_STATE_NONE )
	{
		rtw_p2p_set_pre_state( pwdinfo,rtw_p2p_state( pwdinfo ) );
		rtw_p2p_set_state(pwdinfo, P2P_STATE_FIND_PHASE_SEARCH);
		rtw_p2p_findphase_ex_set(pwdinfo, P2P_FINDPHASE_EX_FULL);
		rtw_free_network_queue(padapter, _TRUE);
	}
#endif //CONFIG_P2P

	_rtw_memset(ssid, 0, sizeof(NDIS_802_11_SSID)*RTW_SSID_SCAN_AMOUNT);
    _rtw_memset(&parm, 0, sizeof(struct sitesurvey_parm));


//XXX: Raj (enable below for specific scan)
#if 0
	if (iwcp->param1 == sizeof(struct iw_scan_req)) 
	{
		struct iw_scan_req *req = (struct iw_scan_req *)iwcp->wc_apps_data;
	
		if (wrqu->data.flags & IW_SCAN_THIS_ESSID)
		{
			int len = min((int)req->essid_len, IW_ESSID_MAX_SIZE);

			_rtw_memcpy(ssid[0].Ssid, req->essid, len);
			ssid[0].SsidLength = len;	

			RTW_INFO("IW_SCAN_THIS_ESSID, ssid=%s, len=%d\n", req->essid, req->essid_len);
		
			_enter_critical_bh(&pmlmepriv->lock, &irqL);				
		
			_status = rtw_sitesurvey_cmd(padapter, ssid, 1, NULL, 0);
		
			_exit_critical_bh(&pmlmepriv->lock, &irqL);
			
		}
		else if (req->scan_type == IW_SCAN_TYPE_PASSIVE)
		{
			RTW_INFO("rtw_wx_set_scan, req->scan_type == IW_SCAN_TYPE_PASSIVE\n");
		}
		
	}
	else
#endif
	if(	iwcp->param1 >= WEXT_CSCAN_HEADER_SIZE
		&& _rtw_memcmp(iwcp->wc_apps_data, WEXT_CSCAN_HEADER, WEXT_CSCAN_HEADER_SIZE) == _TRUE
	)
	{
		int len = iwcp->param1 - WEXT_CSCAN_HEADER_SIZE;
		char *pos = (char *)((char *)iwcp->wc_apps_data + WEXT_CSCAN_HEADER_SIZE);
		char section;
		char sec_len;
		int ssid_index = 0;

		//RTW_INFO("%s COMBO_SCAN header is recognized\n", __FUNCTION__);
	    RTW_INFO("sfsffasf bssid_list_scan %s %d \n",__FUNCTION__,__LINE__);
		
        while(len >= 1) {
            section = *(pos++); len-=1;

            switch(section) {
                case WEXT_CSCAN_SSID_SECTION:
                    //RTW_INFO("WEXT_CSCAN_SSID_SECTION\n");
                    if(len < 1) {
                        len = 0;
                        break;
                    }

                    sec_len = *(pos++); len-=1;

                    if(sec_len>0 && sec_len<=len) {
                        ssid[ssid_index].SsidLength = sec_len;
                        _rtw_memcpy(ssid[ssid_index].Ssid, pos, ssid[ssid_index].SsidLength);
                        //RTW_INFO("%s COMBO_SCAN with specific ssid:%s, %d\n", __FUNCTION__
                        //	, ssid[ssid_index].Ssid, ssid[ssid_index].SsidLength);
                        ssid_index++;
                    }

                    pos+=sec_len; len-=sec_len;
                    break;


                case WEXT_CSCAN_CHANNEL_SECTION:
                    //RTW_INFO("WEXT_CSCAN_CHANNEL_SECTION\n");
                    pos+=1; len-=1;
                    break;
                case WEXT_CSCAN_ACTV_DWELL_SECTION:
                    //RTW_INFO("WEXT_CSCAN_ACTV_DWELL_SECTION\n");
                    pos+=2; len-=2;
                    break;
                case WEXT_CSCAN_PASV_DWELL_SECTION:
                    //RTW_INFO("WEXT_CSCAN_PASV_DWELL_SECTION\n");
                    pos+=2; len-=2;					
                    break;
                case WEXT_CSCAN_HOME_DWELL_SECTION:
                    //RTW_INFO("WEXT_CSCAN_HOME_DWELL_SECTION\n");
                    pos+=2; len-=2;
                    break;
                case WEXT_CSCAN_TYPE_SECTION:
                    //RTW_INFO("WEXT_CSCAN_TYPE_SECTION\n");
                    pos+=1; len-=1;
                    break;
#if 0
                case WEXT_CSCAN_NPROBE_SECTION:
                    RTW_INFO("WEXT_CSCAN_NPROBE_SECTION\n");
                    break;
#endif

                default:
                    //RTW_INFO("Unknown CSCAN section %c\n", section);
                    len = 0; // stop parsing
            }
            //RTW_INFO("len:%d\n", len);

        }

        rtw_init_sitesurvey_parm(padapter, &parm);
        _rtw_memcpy(&parm.ssid[0].Ssid, &scan_req->essid, len);
        parm.ssid[0].SsidLength = len;
        parm.ssid_num = 1;
        
        RTW_INFO("IW_SCAN_THIS_ESSID, ssid=%s, len=%d\n", scan_req->essid, scan_req->essid_len);
        
        _status = rtw_set_802_11_bssid_list_scan(padapter, &parm);

		//jeff: it has still some scan paramater to parse, we only do this now...
		//_status = rtw_set_802_11_bssid_list_scan(padapter, ssid, RTW_SSID_SCAN_AMOUNT);
		
	} else if(scan_req->flags == WC_SCAN_THIS_ESSID)
	{
		_rtw_memcpy(&parm.ssid[0].Ssid, scan_req->essid, scan_req->essid_len);
		parm.ssid[0].SsidLength = scan_req->essid_len;
        parm.ssid_num = 1;
		RTW_INFO("%s, ssid=%s, len=%d\n",__func__,  scan_req->essid, scan_req->essid_len);
		_status = rtw_set_802_11_bssid_list_scan(padapter, &parm);
	}else	
	{
        _status = rtw_set_802_11_bssid_list_scan(padapter, NULL);

	}

	if(_status == _FALSE)
		ret = -1;

exit:
#ifdef DBG_IOCTL
    RTW_INFO("DBG_IOCTL %s:%d return %d\n",__FUNCTION__, __LINE__, ret);
#endif



	return ret;	
}

static int rtw_wx_abort_scan(void *dev, struct rtw_wc_param *iwcp)
{
	struct net_device *netdev = rtw_netdev[0];
	_adapter *padapter = (_adapter *)rtw_netdev_priv(netdev);

	rtw_scan_abort(padapter);
}


static int rtw_wx_site_survey(void *dev, struct rtw_wc_param *iwcp)
{
    rtw_wc_bss_info *bss_info = (rtw_wc_bss_info *)iwcp->wc_apps_data;
    _irqL	irqL;
    _list					*plist, *phead;
    struct net_device *netdev = rtw_get_netdev(dev);
	_adapter *padapter = (_adapter *)rtw_netdev_priv(netdev);
	struct rf_ctl_t *rfctl = adapter_to_rfctl(padapter);
	RT_CHANNEL_INFO *chset = rfctl->channel_set;
    struct	mlme_priv	*pmlmepriv = &(padapter->mlmepriv);
    _queue				*queue	= &(pmlmepriv->scanned_queue);
    struct	wlan_network	*pnetwork = NULL;
    int ret = 0;
    u32 cnt=0;
    u32 wait_for_surveydone;
    sint wait_status;
    u8 ch;

#ifdef CONFIG_P2P
	struct	wifidirect_info*	pwdinfo = &padapter->wdinfo;
#endif //CONFIG_P2P

#ifdef DBG_IOCTL
	RTW_INFO("DBG_IOCTL %s:%d\n", __FUNCTION__, __LINE__);
#endif

	if (adapter_to_pwrctl(padapter)->brfoffbyhw && rtw_is_drv_stopped(padapter)) {
		ret = -EINVAL;
		goto exit;
	}
      
#ifdef CONFIG_P2P
    if(!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE))
    {
        //	P2P is enabled
		if ( padapter->chip_type == RTL8192D )
			wait_for_surveydone = 300;	//	Because the 8192du supports more channels.
		else
			wait_for_surveydone = 200;
	}
	else
	{
		//	P2P is disabled
		wait_for_surveydone = 100;
	}
#else
	{
		wait_for_surveydone = 100;
	}
#endif //CONFIG_P2P


    wait_status = _FW_UNDER_SURVEY
#ifndef CONFIG_ANDROID
        |_FW_UNDER_LINKING
#endif
        ;

    while(check_fwstate(pmlmepriv, wait_status) == _TRUE)
    {	
        rtw_msleep_os(30);
        cnt++;
        if(cnt > wait_for_surveydone )
            break;
    }

    _enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);

    phead = get_list_head(queue);
    plist = get_next(phead);

    cnt = 0;
    while(1)
    {
        if (rtw_end_of_queue_search(phead,plist)== _TRUE) {
            break;
        }

        pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
        ch = pnetwork->network.Configuration.DSConfig;

        //report network only if the current channel set contains the channel to which this network belongs
        if(rtw_chset_search_ch(chset, ch) >= 0
            && rtw_mlme_band_check(padapter, ch) == _TRUE
#ifdef CONFIG_VALIDATE_SSID
            && _TRUE == rtw_validate_ssid(&(pnetwork->network.Ssid))
#endif
          && (!IS_DFS_SLAVE_WITH_RD(rfctl)
              || rtw_odm_dfs_domain_unknown(rfctl_to_dvobj(rfctl))
              || !rtw_chset_is_ch_non_ocp(chset, ch))
          )
        {
			if (cnt >= SCAN_AP_LIMIT) {
				RTW_INFO("cnt value > SCAN_AP_LIMIT\n");
				break;
			}
				
            ret = translate_scan(padapter,&bss_info[cnt], pnetwork);
            if (ret == 0) //To get the exact count in case of scanning p2p devices
				cnt++;
        }

        plist = get_next(plist);
    }        

    _exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);

exit:

    iwcp->param2 = cnt;
    return ret;
}

static int rtw_wx_get_scan(struct net_device *dev, struct rtw_wc_param *iwcp)
{
	_irqL	irqL;
	_list					*plist, *phead;
	struct net_device *netdev = rtw_get_netdev(dev);
	_adapter *padapter = (_adapter *)rtw_netdev_priv(netdev);
	struct rf_ctl_t *rfctl = adapter_to_rfctl(padapter);
	RT_CHANNEL_INFO *chset = rfctl->channel_set;
	struct	mlme_priv	*pmlmepriv = &(padapter->mlmepriv);
	_queue				*queue	= &(pmlmepriv->scanned_queue);
	struct	wlan_network	*pnetwork = NULL;
	int ret = 0;
	u32 cnt=0;
	u32 wait_for_surveydone;
	sint wait_status;
    u8 ch;
    
#ifdef CONFIG_CONCURRENT_MODE
	//PADAPTER pbuddy_adapter = padapter->pbuddy_adapter;
	//struct mlme_priv *pbuddy_mlmepriv = &(pbuddy_adapter->mlmepriv);	
#endif
#ifdef CONFIG_P2P
	struct	wifidirect_info*	pwdinfo = &padapter->wdinfo;
#endif //CONFIG_P2P

    rtw_wc_bss_info *bss_info;
	
    RTW_INFO("rtw_wx_get_scan\n");
	RTW_INFO(" Start of Query SIOCGIWSCAN .\n");

#if 1 //def DBG_IOCTL
    RTW_INFO("DBG_IOCTL %s:%d\n",__FUNCTION__, __LINE__);
#endif

    if (adapter_to_pwrctl(padapter)->brfoffbyhw && rtw_is_drv_stopped(padapter)) {
        ret = -EINVAL;
        goto exit;
    }

    if ((bss_info = (rtw_wc_bss_info *)rtw_malloc((sizeof(rtw_wc_bss_info)))) == NULL) {
        goto exit;
    }

/*
#ifdef CONFIG_CONCURRENT_MODE
	if(padapter->iface_type > PRIMARY_IFACE)
	{
		ret = -EINVAL;
		goto exit;
	}
#endif
*/	
	
#ifdef CONFIG_P2P
        if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE))
            wait_for_surveydone = 200;
        else {
            /*  P2P is disabled */
            wait_for_surveydone = 100;
        }
#else
        {
            wait_for_surveydone = 100;
        }
#endif /* CONFIG_P2P */


/*
#ifdef CONFIG_CONCURRENT_MODE	
	if(pmlmepriv->scanning_via_buddy_intf == _TRUE)
	{
		pmlmepriv->scanning_via_buddy_intf = _FALSE;//reset

		// change pointers to buddy interface
		padapter = pbuddy_adapter;
		pmlmepriv = pbuddy_mlmepriv;
		queue = &(pbuddy_mlmepriv->scanned_queue);		
		
	}
#endif // CONFIG_CONCURRENT_MODE			
*/

	wait_status = _FW_UNDER_SURVEY
#ifndef CONFIG_ANDROID
        |_FW_UNDER_LINKING
#endif
        ;

#ifdef CONFIG_DUALMAC_CONCURRENT
	while(dc_check_fwstate(padapter, wait_status)== _TRUE)
	{
		rtw_msleep_os(30);
		cnt++;
		if(cnt > wait_for_surveydone )
			break;
	}
#endif // CONFIG_DUALMAC_CONCURRENT

 	while(check_fwstate(pmlmepriv, wait_status) == _TRUE)
	{	
		rtw_msleep_os(30);
		cnt++;
		if(cnt > wait_for_surveydone )
			break;
	}

	_enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);

	phead = get_list_head(queue);
	plist = get_next(phead);
       
    cnt = 0;
	while(1)
    {
        if (rtw_end_of_queue_search(phead,plist)== _TRUE) {
            printk("Breaking...%x %x \n",phead,phead->next);
            break;
        }

        pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
        ch = pnetwork->network.Configuration.DSConfig;

        //report network only if the current channel set contains the channel to which this network belongs
        if(rtw_chset_search_ch(chset, ch) >= 0
            && rtw_mlme_band_check(padapter, ch) == _TRUE
#ifdef CONFIG_VALIDATE_SSID
            && _TRUE == rtw_validate_ssid(&(pnetwork->network.Ssid))
#endif
          && (!IS_DFS_SLAVE_WITH_RD(rfctl)
              || rtw_odm_dfs_domain_unknown(rfctl_to_dvobj(rfctl))
              || !rtw_chset_is_ch_non_ocp(chset, ch))
          )
        {
			ret = translate_scan(padapter,bss_info, pnetwork);
            if (ret == 0) //To get the exact count in case of scanning p2p devices
				cnt++;
            /* Now call the User get_scan callback handler */
            //((rtw_wc_scan_cb)iwcp->wc_apps_data)(bss_info);
        }

        plist = get_next(plist);
    }        

	if (bss_info)
		rtw_mfree((u8*)bss_info,sizeof(rtw_wc_bss_info));

	_exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);

exit:
    
#ifdef DBG_IOCTL
    RTW_INFO("DBG_IOCTL %s:%d return %d\n",__FUNCTION__, __LINE__, ret);
#endif
    iwcp->param2 = cnt;

    return ret ;
}


static int rtw_wx_get_scan_count(struct net_device *dev, struct rtw_wc_param *iwcp)
{
	_irqL	irqL;
	_list					*plist, *phead;
	struct net_device *netdev = rtw_get_netdev(dev);
	_adapter *padapter = (_adapter *)rtw_netdev_priv(netdev);
	struct rf_ctl_t *rfctl = adapter_to_rfctl(padapter);
	RT_CHANNEL_INFO *chset = rfctl->channel_set;
	struct	mlme_priv	*pmlmepriv = &(padapter->mlmepriv);
	_queue				*queue	= &(pmlmepriv->scanned_queue);
	struct	wlan_network	*pnetwork = NULL;
	int ret = 0;
	u32 cnt=0;
	u32 wait_for_surveydone;
	sint wait_status;
    u8 ch;

#ifdef CONFIG_P2P
	struct	wifidirect_info*	pwdinfo = &padapter->wdinfo;
#endif //CONFIG_P2P

    if (adapter_to_pwrctl(padapter)->brfoffbyhw && rtw_is_drv_stopped(padapter)) {
        ret = -EINVAL;
        goto exit;
    }
	
#ifdef CONFIG_P2P
	if(!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE))
	{
		//	P2P is enabled
		if ( padapter->chip_type == RTL8192D )
			wait_for_surveydone = 300;	//	Because the 8192du supports more channels.
		else
			wait_for_surveydone = 200;
	}
	else
	{
		//	P2P is disabled
		wait_for_surveydone = 100;
	}
#else
	{
		wait_for_surveydone = 100;
	}
#endif //CONFIG_P2P

	wait_status = _FW_UNDER_SURVEY
#ifndef CONFIG_ANDROID
		|_FW_UNDER_LINKING
#endif
		;

#ifdef CONFIG_DUALMAC_CONCURRENT
	while(dc_check_fwstate(padapter, wait_status)== _TRUE)
	{
		rtw_msleep_os(30);
		cnt++;
		if(cnt > wait_for_surveydone )
			break;
	}
#endif // CONFIG_DUALMAC_CONCURRENT

	while(check_fwstate(pmlmepriv, wait_status) == _TRUE)
	{	
		rtw_msleep_os(30);
		cnt++;
		if(cnt > wait_for_surveydone )
			break;
	}

	_enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);

	phead = get_list_head(queue);
	plist = get_next(phead);

	cnt = 0;
	while(1)
	{
		if (rtw_end_of_queue_search(phead,plist)== _TRUE) {
			break;
		}

		pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);

		if(rtw_chset_search_ch(chset, ch) >= 0
            && rtw_mlme_band_check(padapter, ch) == _TRUE
#ifdef CONFIG_VALIDATE_SSID
            && _TRUE == rtw_validate_ssid(&(pnetwork->network.Ssid))
#endif
          && (!IS_DFS_SLAVE_WITH_RD(rfctl)
              || rtw_odm_dfs_domain_unknown(rfctl_to_dvobj(rfctl))
              || !rtw_chset_is_ch_non_ocp(chset, ch))
		  )
		{
			cnt++;
		}
		plist = get_next(plist);
	}        

	_exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
exit:		
		

	iwcp->param2 = cnt;
	return ret ;
}

//s1. rtw_set_802_11_infrastructure_mode()
//s2. set_802_11_authenticaion_mode()
//s3. set_802_11_encryption_mode()
//s4. rtw_set_802_11_ssid()
static int rtw_wx_set_essid(struct net_device *dev, struct rtw_wc_param *iwcp) 
{
    _irqL irqL;
    struct net_device *netdev = rtw_get_netdev(dev);
	_adapter *padapter = (_adapter *)rtw_netdev_priv(netdev);
    struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
    _queue *queue = &pmlmepriv->scanned_queue;
    _list *phead;
    struct wlan_network *pnetwork = NULL;
    NDIS_802_11_AUTHENTICATION_MODE authmode;	
    NDIS_802_11_SSID ndis_ssid;	
    u8 *dst_ssid, *src_ssid;

    int ret = 0, len;

    


#ifdef DBG_IOCTL
    RTW_INFO("DBG_IOCTL %s:%d\n",__FUNCTION__, __LINE__);
#endif


#if 0
#ifdef CONFIG_CONCURRENT_MODE
    if(padapter->iface_type > PRIMARY_IFACE)
    {
        ret = -EINVAL;
        goto exit;
    }
#endif
#endif


#ifdef CONFIG_CONCURRENT_MODE
    if (check_buddy_fwstate(padapter, _FW_UNDER_SURVEY|_FW_UNDER_LINKING) == _TRUE)
    {		
        RTW_INFO("set ssid, but buddy_intf is under scanning or linking\n");

        ret = -EINVAL;

        goto exit;
    }
#endif

#ifdef CONFIG_DUALMAC_CONCURRENT
    if (dc_check_fwstate(padapter, _FW_UNDER_SURVEY|_FW_UNDER_LINKING)== _TRUE)
    {
        RTW_INFO("set bssid, but buddy_intf is under scanning or linking\n");
        ret = -EINVAL;
        goto exit;
    }
#endif

    RTW_INFO("+rtw_wx_set_essid: fw_state=0x%08x\n", get_fwstate(pmlmepriv));
    if(_FAIL == rtw_pwr_wakeup(padapter))
    {		
        ret = -1;
        goto exit;
    }

    if(!padapter->bup){
        ret = -1;
        goto exit;
    }

    if (iwcp->param1 > IW_ESSID_MAX_SIZE) {
        ret= -E2BIG;
        goto exit;
    }

    if(check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
        ret = -1;
        goto exit;
    }		

    authmode = (NDIS_802_11_AUTHENTICATION_MODE) padapter->securitypriv.ndisauthtype;
    RTW_INFO("=>%s AM:%d\n",__FUNCTION__,authmode);
    if (iwcp->param1)
    {
        // Commented by Albert 20100519
        // We got the codes in "set_info" function of iwconfig source code.
        //	=========================================
        //	wrq.u.essid.length = strlen(essid) + 1;
        //	if(we_kernel_version > 20)
        //		wrq.u.essid.length--;
        //	=========================================
        //	That means, if the WIRELESS_EXT less than or equal to 20, the correct ssid len should subtract 1.
        len = (iwcp->param1 < IW_ESSID_MAX_SIZE) ? iwcp->param1 : IW_ESSID_MAX_SIZE;

//        if( iwcp->param1 != 33 )
//            RTW_INFO("ssid=%s, len=%d\n", iwcp->wc_apps_data, iwcp->param1);

        _rtw_memset(&ndis_ssid, 0, sizeof(NDIS_802_11_SSID));
        ndis_ssid.SsidLength = len;
        _rtw_memcpy(ndis_ssid.Ssid, iwcp->wc_apps_data, len);		
        src_ssid = ndis_ssid.Ssid;

        RTW_INFO("rtw_wx_set_essid: ssid=[%s]\n", src_ssid);
        _enter_critical_bh(&queue->lock, &irqL);
        phead = get_list_head(queue);
        pmlmepriv->pscanned = get_next(phead);

        while (1)
        {			
            if (rtw_end_of_queue_search(phead, pmlmepriv->pscanned) == _TRUE)
            {
#if 0			
                if(check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == _TRUE)
                {
                    rtw_set_802_11_ssid(padapter, &ndis_ssid);

                    goto exit;                    
                }
                else
                {
                    RTW_INFO(_module_rtl871x_ioctl_os_c,_drv_info_,("rtw_wx_set_ssid(): scanned_queue is empty\n"));
                    ret = -EINVAL;
                    goto exit;
                }
#endif			
                
                RTW_INFO("rtw_wx_set_essid: scan_q is empty, set ssid to check if scanning again!\n");

                break;
            }

            pnetwork = LIST_CONTAINOR(pmlmepriv->pscanned, struct wlan_network, list);

            pmlmepriv->pscanned = get_next(pmlmepriv->pscanned);

            dst_ssid = pnetwork->network.Ssid.Ssid;

            
            
            RTW_INFO("rtw_wx_set_essid: dst_ssid=%s\n",
                     pnetwork->network.Ssid.Ssid);
            if ((_rtw_memcmp(dst_ssid, src_ssid, ndis_ssid.SsidLength) == _TRUE) &&
                    (pnetwork->network.Ssid.SsidLength==ndis_ssid.SsidLength))
            {
                RTW_INFO("rtw_wx_set_essid: find match, set infra mode\n");

                if(check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == _TRUE)
                {
                    if(pnetwork->network.InfrastructureMode != pmlmepriv->cur_network.network.InfrastructureMode)
                        continue;
                }	

                if (rtw_set_802_11_infrastructure_mode(padapter, pnetwork->network.InfrastructureMode, 0) == _FALSE)
                {
                    ret = -1;
                    _exit_critical_bh(&queue->lock, &irqL);
                    goto exit;
                }

                break;			
            }
        }
        _exit_critical_bh(&queue->lock, &irqL);
        RTW_INFO("set ssid: set_802_11_auth. mode=%d\n", authmode);
        rtw_set_802_11_authentication_mode(padapter, authmode);
        //set_802_11_encryption_mode(padapter, padapter->securitypriv.ndisencryptstatus);
        if (rtw_set_802_11_ssid(padapter, &ndis_ssid) == _FALSE) {
            ret = -1;
            goto exit;
        }	
    }			

exit:

    RTW_INFO("<=%s, ret %d\n",__FUNCTION__, ret);

#ifdef DBG_IOCTL
    RTW_INFO("DBG_IOCTL %s:%d return %d\n",__FUNCTION__, __LINE__, ret);
#endif

    

    return ret;	
}

static int rtw_wx_get_essid(struct net_device *dev, struct rtw_wc_param *iwcp) 
{
	u32 len;
    int ret = 0;
	struct net_device *netdev = rtw_get_netdev(dev);
	_adapter *padapter = (_adapter *)rtw_netdev_priv(netdev);
	struct	mlme_priv	*pmlmepriv = &(padapter->mlmepriv);
	WLAN_BSSID_EX  *pcur_bss = &pmlmepriv->cur_network.network;

	RTW_INFO("rtw_wx_get_essid\n");

	if ( (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) ||
	      (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == _TRUE))
    {
        len = pcur_bss->Ssid.SsidLength;

        iwcp->param1 = len;

        _rtw_memcpy(iwcp->wc_apps_data, pcur_bss->Ssid.Ssid, len);

    }
	else
    {
        ret = -1;
        goto exit;
    }

exit:
	return ret;
	
}

static int rtw_wx_set_rate(struct net_device *dev, struct rtw_wc_param *iwcp) 
{
    int	i, ret = 0;
    struct net_device *netdev = rtw_get_netdev(dev);
	_adapter *padapter = (_adapter *)rtw_netdev_priv(netdev);
    u8	datarates[NumRates];
    int	target_rate = iwcp->param1; 
    u32	fixed = iwcp->param2;  //for fixed
    u32	ratevalue = 0;
    u8 mpdatarate[NumRates]={11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0xff};
    
    RTW_INFO(" rtw_wx_set_rate \n");
    RTW_INFO("target_rate = %d, fixed = %d\n",target_rate,fixed);

    if(target_rate == -1){
        ratevalue = 11;
        goto set_rate;
    }
    target_rate = target_rate/100000;

    switch(target_rate){
        case 10:
            ratevalue = 0;
            break;
        case 20:
            ratevalue = 1;
            break;
        case 55:
            ratevalue = 2;
            break;
        case 60:
            ratevalue = 3;
            break;
        case 90:
            ratevalue = 4;
            break;
        case 110:
            ratevalue = 5;
            break;
        case 120:
            ratevalue = 6;
            break;
        case 180:
            ratevalue = 7;
            break;
        case 240:
            ratevalue = 8;
            break;
        case 360:
            ratevalue = 9;
            break;
        case 480:
            ratevalue = 10;
            break;
        case 540:
            ratevalue = 11;
            break;
        default:
            ratevalue = 11;
            break;
    }

set_rate:

    for(i=0; i<NumRates; i++)
    {
        if(ratevalue==mpdatarate[i])
        {
            datarates[i] = mpdatarate[i];
            if(fixed == 0)
                break;
        }
        else{
            datarates[i] = 0xff;
        }

        RTW_INFO("datarate_inx=%d\n",datarates[i]);
    }

    if( rtw_setdatarate_cmd(padapter, datarates) !=_SUCCESS){
        RTW_INFO("rtw_wx_set_rate Fail!!!\n");
        ret = -1;
    }

    

    return ret;
}

static int rtw_wx_get_rate(struct net_device *dev, struct rtw_wc_param *iwcp) 
{	
	u16 max_rate = 0;

	max_rate = rtw_get_cur_max_rate((_adapter *)rtw_netdev_priv(dev));

	if(max_rate == 0)
		return -EPERM;
	
	iwcp->param1 = max_rate * 100000;

	return 0;
}
static int rtw_wx_support_rate(struct net_device *dev, struct rtw_wc_param *iwcp) 
{
	int i=0,j;
	struct net_device *netdev = rtw_netdev[0];
	_adapter *padapter = (_adapter *)rtw_netdev_priv(netdev);
	struct mlme_priv	*pmlmepriv = &padapter->mlmepriv;
	int	sta_bssrate_len = 0;
	unsigned char	*sta_bssrate = (unsigned char	*)(iwcp->wc_apps_data);
	u16	rate = 0;
	WLAN_BSSID_EX	*pcur_bss = &pmlmepriv->cur_network.network;

	sta_bssrate_len=12;
    sta_bssrate[0] = 10;
    sta_bssrate[1] = 20;
    sta_bssrate[2] = 55;
    sta_bssrate[3] = 110;
    sta_bssrate[4] = 60;
    sta_bssrate[5] = 90;
    sta_bssrate[6] = 120;
    sta_bssrate[7] = 180;
    sta_bssrate[8] = 240;
    sta_bssrate[9] = 360;
    sta_bssrate[10] = 480;
    sta_bssrate[11] = 540;

#if 0
	if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == _TRUE)
		sta_bssrate_len = ratetbl2rateset(padapter, sta_bssrate);

	for(j=0;j<sta_bssrate_len;j++)
	{
		sta_bssrate[j] = (sta_bssrate[j]&0x7F)*5;
		RTW_INFO("%s,rate:%d\n",__func__,sta_bssrate[j]);
	}

	
	RTW_INFO("%s\n",__func__);
	while ((pcur_bss->SupportedRates[i] != 0) && (pcur_bss->SupportedRates[i] != 0xFF)) {
		
		rate = pcur_bss->SupportedRates[i] & 0x7F;/*AP support rates*/
		/*check STA  support rate or not */
		if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == _TRUE) {
			for (j = 0; j < sta_bssrate_len; j++) {
				/* Avoid the proprietary data rate (22Mbps) of Handlink WSG-4000 AP */
				if ((rate | IEEE80211_BASIC_RATE_MASK)== (sta_bssrate[j] | IEEE80211_BASIC_RATE_MASK)) {
					sta_bssrate[i] = pcur_bss->SupportedRates[i];
					RTW_INFO("%s, sta mode rate:%d\n",__func__,sta_bssrate[i]);
					break;
				}
				else{

				}
			}
			
		} 
		else {			
			sta_bssrate[i] = pcur_bss->SupportedRates[i];
			RTW_INFO("%s, 123 rate:%d\n",__func__,sta_bssrate[i]);
			sta_bssrate_len++;
		}
		i++;
	}
	RTW_INFO("%s rate num:%d\n",__func__,sta_bssrate_len);
#endif
exit:
	iwcp->param1 = sta_bssrate_len;
	
	return 0;	
}

static int rtw_wx_set_rts(struct net_device *dev, struct rtw_wc_param *iwcp) 
{
	struct net_device *netdev = rtw_get_netdev(dev);
	_adapter *padapter = (_adapter *)rtw_netdev_priv(netdev);

	

#if 0    
	if (iwcp->param1 & rts.disabled)
		padapter->registrypriv.rts_thresh = 2347;
	else 
#endif
    {
        if ((int)iwcp->param1 < 0 ||
                iwcp->param1 > 2347)
            return -EINVAL;

        padapter->registrypriv.rts_thresh = iwcp->param1;
    }
	RTW_INFO("%s, rts_thresh=%d\n", __func__, padapter->registrypriv.rts_thresh);
			
	return 0;

}

static int rtw_wx_get_rts(struct net_device *dev, struct rtw_wc_param *iwcp) 
{
	struct net_device *netdev = rtw_get_netdev(dev);
	_adapter *padapter = (_adapter *)rtw_netdev_priv(netdev);
	
	

	RTW_INFO("%s, rts_thresh=%d\n", __func__, padapter->registrypriv.rts_thresh);	
	
	iwcp->param1 = padapter->registrypriv.rts_thresh;
	//wrqu->rts.disabled = (wrqu->rts.value == DEFAULT_RTS_THRESHOLD);
	
	
	
	return 0;
}

static int rtw_wx_set_frag(struct net_device *dev, struct rtw_wc_param *iwcp) 
{
	struct net_device *netdev = rtw_get_netdev(dev);
	_adapter *padapter = (_adapter *)rtw_netdev_priv(netdev);

	
	
#if 0
	if (iwcp->param1 ) //
		padapter->xmitpriv.frag_len = MAX_FRAG_THRESHOLD;
	else
#endif
    {
		if (iwcp->param1 < MIN_FRAG_THRESHOLD ||
		    iwcp->param1 > MAX_FRAG_THRESHOLD)
			return -EINVAL;
		
		padapter->xmitpriv.frag_len = iwcp->param1 & ~0x1;
	}

	RTW_INFO("%s, frag_len=%d\n", __func__, padapter->xmitpriv.frag_len);
	
	
	
	return 0;
	
}

static int rtw_wx_get_frag(struct net_device *dev, struct rtw_wc_param *iwcp) 
{
	struct net_device *netdev = rtw_get_netdev(dev);
	_adapter *padapter = (_adapter *)rtw_netdev_priv(netdev);
	
	

	RTW_INFO("%s, frag_len=%d\n", __func__, padapter->xmitpriv.frag_len);
	
	iwcp->param1 = padapter->xmitpriv.frag_len;
	//wrqu->frag.disabled = (wrqu->frag.value == DEFAULT_FRAG_THRESHOLD);
	
	
	
	return 0;
}

static int rtw_wx_get_retry(struct net_device *dev, struct rtw_wc_param *iwcp) 
{
    iwcp->param1 = 7;
    return 0;

}	
static inline int is_zero_ether_addr(const u8 *a)
{
	return !(a[0] | a[1] | a[2] | a[3] | a[4] | a[5]);
}

static inline int is_broadcast_ether_addr(const u8 *a)
{
	return (a[0] & a[1] & a[2] & a[3] & a[4] & a[5]) == 0xff;
}

struct Key_Params {
    unsigned char *key;    /**< Key content */
    unsigned char *seq;    /**< Content of a Temporal Key Integrity Protocol (TKIP) or Counter Mode Cipher Block Chaining
                      * Message Authentication Code Protocol (CCMP) key
                      */
    int keyLen;  /**< Key length */
    int seqLen;  /**< Length of a TKIP or CCMP key */
    unsigned int cipher; /**< Cipher suite */
};

static int rtw_wx_add_key(struct net_device *dev, struct rtw_wc_param *iwcp) 
{
	u8 ret = 0;
	u32 param_len;
	struct ieee_param *param = NULL;
	u8 *mac_addr=(u8*)iwcp->wc_apps_data;
	u8 key_index = iwcp->param1;
	bool pairwise= iwcp->param2;
	struct Key_Params *params = (struct Key_Params*)iwcp->wc_apps_data1;
	char *alg_name;
	struct net_device *netdev = rtw_get_netdev(dev);
	_adapter *padapter = (_adapter *)rtw_netdev_priv(netdev);
	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;


	param_len = sizeof(struct ieee_param) + params->keyLen;
	param = rtw_malloc(param_len);
	if (param == NULL)
		return -1;


	_rtw_memset(param->sta_addr, 0xff, ETH_ALEN);


	switch (params->cipher) {
		case WC_AUTH_CIPHER_NONE:
			/* todo: remove key */
			/* remove = 1;	 */
			alg_name = "none";
			break;
		case WLAN_CIPHER_SUITE_WEP40:
		case WLAN_CIPHER_SUITE_WEP104:
			alg_name = "WEP";
			break;
		case WLAN_CIPHER_SUITE_TKIP:
			alg_name = "TKIP";
			break;
		case WLAN_CIPHER_SUITE_CCMP:
			alg_name = "CCMP";
			break;
#ifdef CONFIG_IEEE80211W
		case WLAN_CIPHER_SUITE_AES_CMAC:
			alg_name = "BIP";
			break;
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_WAPI_SUPPORT
		case WLAN_CIPHER_SUITE_SMS4:
			alg_name = "SMS4";
			if (pairwise == NL80211_KEYTYPE_PAIRWISE) {
				if (key_index != 0 && key_index != 1) {
					ret = -2;
					goto exit;
				}
				_rtw_memcpy((void *)param->sta_addr, (void *)mac_addr, ETH_ALEN);
			} else
				RTW_INFO("mac_addr is null\n");
			RTW_INFO("rtw_wx_set_enc_ext: SMS4 case\n");
			break;
#endif
	
		default:
			ret = -2;
			goto exit;
		}

	strncpy((char *)param->u.crypt.alg, alg_name, IEEE_CRYPT_ALG_NAME_LEN);

	if (!mac_addr || is_broadcast_ether_addr(mac_addr)|| !pairwise) {
			param->u.crypt.set_tx = 0; /* for wpa/wpa2 group key */
		} else {
			param->u.crypt.set_tx = 1; /* for wpa/wpa2 pairwise key */
	}

	if (strcmp(alg_name, "WEP")==0)
	{
		param->u.crypt.set_tx = 1;
	}

	param->u.crypt.idx = key_index;

	if (params->seqLen && params->seq) {
		_rtw_memcpy(param->u.crypt.seq, (u8 *)params->seq, params->seqLen);
		RTW_INFO(FUNC_NDEV_FMT" seq_len:%u, seq:0x%llx\n", FUNC_NDEV_ARG(netdev)
			, params->seqLen, RTW_GET_LE64(param->u.crypt.seq));
	}

	if (params->keyLen && params->key) {
		param->u.crypt.key_len = params->keyLen;
		_rtw_memcpy(param->u.crypt.key, (u8 *)params->key, params->keyLen);
	}

	if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == _TRUE) {
#ifdef CONFIG_TDLS
		if (rtw_tdls_is_driver_setup(padapter) == _FALSE && mac_addr) {
			ptdls_sta = rtw_get_stainfo(&padapter->stapriv, (void *)mac_addr);
			if (ptdls_sta != NULL && ptdls_sta->tdls_sta_state) {
				_rtw_memcpy(ptdls_sta->tpk.tk, params->key, params->key_len);
				rtw_tdls_set_key(padapter, ptdls_sta);
				goto addkey_end;
			}
		}
#endif /* CONFIG_TDLS */
		ret = wpa_set_encryption(netdev, param, param_len);
	} else if (MLME_IS_AP(padapter) || MLME_IS_MESH(padapter)) {
#ifdef CONFIG_AP_MODE
		if (mac_addr)
			_rtw_memcpy(param->sta_addr, (void *)mac_addr, ETH_ALEN);

		ret = rtw_set_encryption(netdev, param, param_len);
#endif
	} else if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == _TRUE
		|| check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == _TRUE
	) {
		ret = wpa_set_encryption(netdev, param, param_len);
	} else
		RTW_INFO("error! fw_state=0x%x\n", pmlmepriv->fw_state);
exit:	
	if (param)
		rtw_mfree(param, param_len);
		return ret;

}

static int rtw_wx_set_default_key(struct net_device *dev, struct rtw_wc_param *iwcp) 
{
	u8 ret = 0;
	u8 keyIndex = iwcp->param1;
	bool unicast =iwcp->param2;
	bool multicas =iwcp->param3;	
	struct net_device *netdev = rtw_get_netdev(dev);
	_adapter *padapter = (_adapter *)rtw_netdev_priv(netdev);
	struct security_priv *psecuritypriv = &padapter->securitypriv;


	if ((keyIndex < WEP_KEYS) && ((psecuritypriv->dot11PrivacyAlgrthm == _WEP40_) || (psecuritypriv->dot11PrivacyAlgrthm == _WEP104_))) { /* set wep default key */
		psecuritypriv->ndisencryptstatus = Ndis802_11Encryption1Enabled;

		psecuritypriv->dot11PrivacyKeyIndex = keyIndex;

		psecuritypriv->dot11PrivacyAlgrthm = _WEP40_;
		psecuritypriv->dot118021XGrpPrivacy = _WEP40_;
		if (psecuritypriv->dot11DefKeylen[keyIndex] == 13) {
			psecuritypriv->dot11PrivacyAlgrthm = _WEP104_;
			psecuritypriv->dot118021XGrpPrivacy = _WEP104_;
		}

		psecuritypriv->bWepDefaultKeyIdxSet = 1; /* set the flag to represent that wep default key has been set */
	}



exit:	
	
	return ret;
}

static int rtw_wx_del_key(struct net_device *dev, struct rtw_wc_param *iwcp) 
{
	u8 keyIndex = iwcp->param1;
	bool pairwise = iwcp->param2;
	u8 *addr = (u8 *)(iwcp->wc_apps_data);
	struct sta_info *stainfo;
	u8 ret = 0;
	char *alg_name;
	u32 param_len;
	u32 key_len = 0;
	struct ieee_param *param = NULL;

	_adapter *padapter = (_adapter *)rtw_netdev_priv(rtw_netdev[0]);		
	struct security_priv *psecuritypriv = &padapter->securitypriv;

	RTW_INFO(FUNC_NDEV_FMT" key_index=%d\n", FUNC_NDEV_ARG(dev), keyIndex);

	if (keyIndex == psecuritypriv->dot11PrivacyKeyIndex)
	{
		//clear the flag of wep default key set.
		psecuritypriv->bWepDefaultKeyIdxSet = 0;
	}
	
	key_len = 32;
	param_len = sizeof(struct ieee_param) + key_len;
	param = (struct ieee_param *)rtw_malloc(param_len);
	if (param == NULL)
		return ENOMEM;
	_rtw_memset(param, 0, param_len);
	
	param->cmd = RTL871X_SET_ENCRYPTION;
	_rtw_memset(param->sta_addr, 0xff, ETH_ALEN);

	alg_name = "none";
	strncpy((char *)param->u.crypt.alg, alg_name, IEEE_CRYPT_ALG_NAME_LEN);			
	param->u.crypt.set_tx = 0;
	param->u.crypt.idx = keyIndex;
	param->u.crypt.key_len = key_len;
	_rtw_memset(param->u.crypt.key, 0, param->u.crypt.key_len);

	ret =  rtw_set_encryption(padapter, param, param_len);	
exit:	
	
	return ret;
}

static int rtw_wx_set_enc(struct net_device *dev, struct rtw_wc_param *iwcp) 
{	
    u32 key;
    int ret = 0;
    u32 keyindex_provided;
    NDIS_802_11_WEP	 wep;	
    NDIS_802_11_AUTHENTICATION_MODE authmode;

    struct net_device *netdev = rtw_get_netdev(dev);
	_adapter *padapter = (_adapter *)rtw_netdev_priv(netdev);
    RTW_INFO("+rtw_wx_set_enc, flags=0x%x\n", iwcp->param2);

    _rtw_memset(&wep, 0, sizeof(NDIS_802_11_WEP));

    key = iwcp->param3;

    	

    if (iwcp->param2 & WC_FLAG_ENCODE_DISABLED)
    {
        RTW_INFO("EncryptionDisabled\n");
        padapter->securitypriv.ndisencryptstatus = Ndis802_11EncryptionDisabled;
        padapter->securitypriv.dot11PrivacyAlgrthm=_NO_PRIVACY_;
        padapter->securitypriv.dot118021XGrpPrivacy=_NO_PRIVACY_;
        padapter->securitypriv.dot11AuthAlgrthm= dot11AuthAlgrthm_Open; //open system
        authmode = Ndis802_11AuthModeOpen;
        padapter->securitypriv.ndisauthtype=authmode;

        goto exit;
    }

    if (key) {
        if (key > WEP_KEYS)
            return -EINVAL;
        key--;
        keyindex_provided = 1;
    } 
    else
    {
        keyindex_provided = 0;
        key = padapter->securitypriv.dot11PrivacyKeyIndex;
        RTW_INFO("rtw_wx_set_enc, key=%d\n", key);
    }

    //set authentication mode	
    if(iwcp->param2 & WC_AUTH_ALG_OPEN_SYSTEM)
    {
        RTW_INFO("rtw_wx_set_enc():WC_ENCODE_OPEN\n");
        padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;//Ndis802_11EncryptionDisabled;

#ifdef CONFIG_PLATFORM_MT53XX
        padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Auto;
#else
        padapter->securitypriv.dot11AuthAlgrthm= dot11AuthAlgrthm_Open;
#endif

        padapter->securitypriv.dot11PrivacyAlgrthm=_NO_PRIVACY_;
        padapter->securitypriv.dot118021XGrpPrivacy=_NO_PRIVACY_;
        authmode = Ndis802_11AuthModeOpen;
        padapter->securitypriv.ndisauthtype=authmode;
    }	
    else if(iwcp->param2 & WC_AUTH_ALG_SHARED_KEY)
    {		
        RTW_INFO("rtw_wx_set_enc():IW_ENCODE_RESTRICTED\n");
        padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;

#ifdef CONFIG_PLATFORM_MT53XX
        padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Auto;
#else
        padapter->securitypriv.dot11AuthAlgrthm= dot11AuthAlgrthm_Shared;
#endif

        padapter->securitypriv.dot11PrivacyAlgrthm=_WEP40_;
        padapter->securitypriv.dot118021XGrpPrivacy=_WEP40_;			
        authmode = Ndis802_11AuthModeShared;
        padapter->securitypriv.ndisauthtype=authmode;
    }
    else
    {
        RTW_INFO("rtw_wx_set_enc():erq->flags=0x%x\n", iwcp->param2);

        padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled;//Ndis802_11EncryptionDisabled;
        padapter->securitypriv.dot11AuthAlgrthm= dot11AuthAlgrthm_Open; //open system
        padapter->securitypriv.dot11PrivacyAlgrthm=_NO_PRIVACY_;
        padapter->securitypriv.dot118021XGrpPrivacy=_NO_PRIVACY_;
        authmode = Ndis802_11AuthModeOpen;
        padapter->securitypriv.ndisauthtype=authmode;
    }

    wep.KeyIndex = key;
    if (iwcp->param1 > 0)
    {
        wep.KeyLength = iwcp->param1 <= 5 ? 5 : 13;
        wep.Length = wep.KeyLength + FIELD_OFFSET(NDIS_802_11_WEP, KeyMaterial);
    }
    else
    {
        wep.KeyLength = 0 ;

        if(keyindex_provided == 1)// set key_id only, no given KeyMaterial(erq->length==0).
        {
            padapter->securitypriv.dot11PrivacyKeyIndex = key;

            RTW_INFO("(keyindex_provided == 1), keyid=%d, key_len=%d\n", key, padapter->securitypriv.dot11DefKeylen[key]);

            switch(padapter->securitypriv.dot11DefKeylen[key])
            {
                case 5:
                    padapter->securitypriv.dot11PrivacyAlgrthm=_WEP40_;					
                    break;
                case 13:
                    padapter->securitypriv.dot11PrivacyAlgrthm=_WEP104_;					
                    break;
                default:
                    padapter->securitypriv.dot11PrivacyAlgrthm=_NO_PRIVACY_;					
                    break;
            }

            goto exit;
        }

    }

    wep.KeyIndex |= 0x80000000;

    _rtw_memcpy(wep.KeyMaterial, iwcp->wc_apps_data, wep.KeyLength);

    if (rtw_set_802_11_add_wep(padapter, &wep) == _FALSE) {
        goto exit;
    }	

exit:
    

    return ret;
}

static int rtw_wx_get_enc(struct net_device *dev, struct rtw_wc_param *iwcp) 
{
    uint key, ret =0;
    struct net_device *netdev = rtw_get_netdev(dev);
	_adapter *padapter = (_adapter *)rtw_netdev_priv(netdev);
    struct	mlme_priv	*pmlmepriv = &(padapter->mlmepriv);
	WLAN_BSSID_EX *pbss_network = (WLAN_BSSID_EX *)&pmlmepriv->cur_network.network;	

    

    if(check_fwstate(pmlmepriv, _FW_LINKED) != _TRUE)
    {
        if(check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) != _TRUE)
        {
            iwcp->param1 = 0;
            iwcp->param2 |= WC_FLAG_ENCODE_DISABLED;
			RTW_INFO("### WIFI_ADHOC_MASTER_STATE ### \n");
            return 0;
        }	
    }	

    if(check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
		iwcp->param1 = 1;
		return 0;
	}

    key = iwcp->param3;

    if (key) {
        if (key > WEP_KEYS)
            return -EINVAL;
        key--;
    } else
    {
        key = padapter->securitypriv.dot11PrivacyKeyIndex;
    }	

    iwcp->param2= (key + 1);

    //if(padapter->securitypriv.ndisauthtype == Ndis802_11AuthModeOpen)
    //{
    //      erq->flags |= IW_ENCODE_OPEN;
    //}	  

    switch(padapter->securitypriv.ndisencryptstatus)
    {
        case Ndis802_11EncryptionNotSupported:
        case Ndis802_11EncryptionDisabled:

            iwcp->param1  = 0; 
            iwcp->param2 |= WC_FLAG_ENCODE_DISABLED;	

            break;

		case Ndis802_11Encryption1Enabled:					

            iwcp->param1 = padapter->securitypriv.dot11DefKeylen[key];		

            if(iwcp->param1)
            {
                _rtw_memcpy(iwcp->wc_apps_data,padapter->securitypriv.dot11DefKey[key].skey, padapter->securitypriv.dot11DefKeylen[key]);

                iwcp->param2 |= WC_FLAG_ENCODE_ENABLED;

                if(padapter->securitypriv.ndisauthtype == Ndis802_11AuthModeOpen)
                {
                    iwcp->param2 |= WC_FLAG_ENCODE_OPEN;
                }
                else if(padapter->securitypriv.ndisauthtype == Ndis802_11AuthModeShared)
                {
                    iwcp->param2 |= WC_FLAG_ENCODE_RESTRICTED;
                }	
            }	
            else
            {
                iwcp->param1  = 0; 
                iwcp->param2 |= WC_FLAG_ENCODE_DISABLED;
            }

            break;

        case Ndis802_11Encryption2Enabled:
        case Ndis802_11Encryption3Enabled:

            iwcp->param1  = 16;
            iwcp->param2 |= (WC_FLAG_ENCODE_ENABLED | WC_FLAG_ENCODE_OPEN | WC_FLAG_ENCODE_NOKEY);

            break;

        default:
            iwcp->param1  = 0; 
            iwcp->param2 |= WC_FLAG_ENCODE_DISABLED;

            break;
    }

    

    return ret;
}				     

static int rtw_wx_set_power(struct net_device *dev, struct rtw_wc_param *iwcp) 
{

	int ret = 0;
	unsigned	mode = iwcp->param1;
	struct net_device *netdev = rtw_get_netdev(dev);
	_adapter *padapter = (_adapter *)rtw_netdev_priv(netdev);
    char *extra = iwcp->wc_apps_data;

	RTW_INFO( "[%s] extra = %s\n", __FUNCTION__, extra );

	if ( _rtw_memcmp( extra, "lps", 4 ) )
	{
		ret = rtw_pm_set_lps(padapter,mode);
	}
	else if ( _rtw_memcmp( extra, "ips", 4 ) )
	{
		ret = rtw_pm_set_ips(padapter,mode);
	}
	else{
		ret = -EINVAL;
	}

	return ret;
}


static int rtw_wx_get_power(struct net_device *dev, struct rtw_wc_param *iwcp) 
{
	struct net_device *netdev = rtw_get_netdev(dev);
	_adapter *padapter = (_adapter *)rtw_netdev_priv(netdev);
	
	
	return 0;

}

static int rtw_wx_set_txpow(struct net_device *dev, struct rtw_wc_param *iwcp)
{
	int ret =0;
	struct net_device *netdev = rtw_netdev[0];
	_adapter *padapter = (_adapter *)rtw_netdev_priv(netdev);
	s32 power;
	u8 txpoweridx_a, txpoweridx_b;
	u8 rate[] = {MGN_1M, MGN_2M, MGN_5_5M, MGN_11M,
		MGN_6M, MGN_9M, MGN_12M, MGN_18M,
		MGN_24M, MGN_36M, MGN_48M, MGN_54M,
		MGN_MCS0, MGN_MCS1, MGN_MCS2, MGN_MCS3,
		MGN_MCS4, MGN_MCS5, MGN_MCS6, MGN_MCS7, 
		MGN_MCS8, MGN_MCS9,MGN_MCS10, MGN_MCS11, 
		MGN_MCS12, MGN_MCS13, MGN_MCS14, MGN_MCS15, 
		MGN_MCS16, MGN_MCS17, MGN_MCS18, MGN_MCS19,
		MGN_MCS20, MGN_MCS21, MGN_MCS22, MGN_MCS23, 
		MGN_MCS24, MGN_MCS25, MGN_MCS26, MGN_MCS27, 
		MGN_MCS28, MGN_MCS29, MGN_MCS30, MGN_MCS31,};
	HAL_DATA_TYPE	*pHalData = NULL;

	u8 path = 0 , i = 0, MaxRate = MGN_6M;
	u8 StartPath = RF_PATH_A, EndPath = RF_PATH_B;
	u8 TxPowerLevel[MAX_RF_PATH];

	power = iwcp->param1;
	txpoweridx_a = power;
	txpoweridx_b = power;
	TxPowerLevel[RF_PATH_A] = txpoweridx_a;
	TxPowerLevel[RF_PATH_B] = txpoweridx_b;


	pHalData = GET_HAL_DATA(padapter);
	EndPath = RF_PATH_A;

	if (pHalData->rf_type == RF_3T3R)
		MaxRate = MGN_MCS23;
	else if (pHalData->rf_type == RF_2T2R)
		MaxRate = MGN_MCS15;
	else
		MaxRate = MGN_MCS7;
	for (path = StartPath; path <= EndPath; path++) {
		for (i = 0; i < sizeof(rate); i++) {
			if (rate[i] > MaxRate)
				break;
			PHY_SetTxPowerIndex(padapter, TxPowerLevel[path], path, rate[i]);
		}
	}
	return ret;
}



static int rtw_wx_set_gen_ie(struct net_device *dev, struct rtw_wc_param *iwcp) 
{
    int ret;
    struct net_device *netdev = rtw_get_netdev(dev);
	_adapter *padapter = (_adapter *)rtw_netdev_priv(netdev);

    ret = rtw_set_wpa_ie(padapter, iwcp->wc_apps_data, iwcp->param1);

    return ret;
}	

static int rtw_wx_set_auth(struct net_device *dev, struct rtw_wc_param *iwcp) 
{
    struct net_device *netdev = rtw_get_netdev(dev);
	_adapter *padapter = (_adapter *)rtw_netdev_priv(netdev);
    struct mlme_priv 	*pmlmepriv = &padapter->mlmepriv;
    struct security_priv *psecuritypriv = &padapter->securitypriv;
    struct mlme_ext_priv	*pmlmeext = &padapter->mlmeextpriv;
    struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
    u32 value = iwcp->param2; //for wapi support
    int ret = 0;

    if (pmlmepriv);
    if (psecuritypriv);
    if (value);

    switch (iwcp->param1 & WC_AUTH_INDEX) { //param->flags

        case WC_AUTH_WPA_VERSION:
#ifdef CONFIG_WAPI_SUPPORT
#ifndef CONFIG_IOCTL_CFG80211
            padapter->wapiInfo.bWapiEnable = false;
            if(value == IW_AUTH_WAPI_VERSION_1)
            {
                padapter->wapiInfo.bWapiEnable = true;
                psecuritypriv->dot11PrivacyAlgrthm = _SMS4_;
                psecuritypriv->dot118021XGrpPrivacy = _SMS4_;
                psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_WAPI;
                pmlmeinfo->auth_algo = psecuritypriv->dot11AuthAlgrthm;
                padapter->wapiInfo.extra_prefix_len = WAPI_EXT_LEN;
                padapter->wapiInfo.extra_postfix_len = SMS4_MIC_LEN;
            }
#endif
#endif
            break;
        case WC_AUTH_CIPHER_PAIRWISE:

            break;
        case WC_AUTH_CIPHER_GROUP:

            break;
        case WC_AUTH_KEY_MGMT:
#ifdef CONFIG_WAPI_SUPPORT
#ifndef CONFIG_IOCTL_CFG80211
            RTW_INFO("rtw_wx_set_auth: IW_AUTH_KEY_MGMT case \n");
            if(value == IW_AUTH_KEY_MGMT_WAPI_PSK)
                padapter->wapiInfo.bWapiPSK = true;
            else
                padapter->wapiInfo.bWapiPSK = false;
            RTW_INFO("rtw_wx_set_auth: IW_AUTH_KEY_MGMT bwapipsk %d \n",padapter->wapiInfo.bWapiPSK);
#endif
#endif
            /*
             *  ??? does not use these parameters
             */
            break;

        case WC_AUTH_TKIP_COUNTERMEASURES:
            {
                if ( iwcp->param2 )
                {  // wpa_supplicant is enabling the tkip countermeasure.
                    padapter->securitypriv.btkip_countermeasure = _TRUE; 
                }
                else
                {  // wpa_supplicant is disabling the tkip countermeasure.
                    padapter->securitypriv.btkip_countermeasure = _FALSE; 
                }
                break;
            }
        case WC_AUTH_DROP_UNENCRYPTED:
            {
                /* HACK:
                 *
                 * wpa_supplicant calls set_wpa_enabled when the driver
                 * is loaded and unloaded, regardless of if WPA is being
                 * used.  No other calls are made which can be used to
                 * determine if encryption will be used or not prior to
                 * association being expected.  If encryption is not being
                 * used, drop_unencrypted is set to false, else true -- we
                 * can use this to determine if the CAP_PRIVACY_ON bit should
                 * be set.
                 */

                if(padapter->securitypriv.ndisencryptstatus == Ndis802_11Encryption1Enabled)
                {
                    break;//it means init value, or using wep, ndisencryptstatus = Ndis802_11Encryption1Enabled, 
                    // then it needn't reset it;
                }

                if(iwcp->param2){
                    padapter->securitypriv.ndisencryptstatus = Ndis802_11EncryptionDisabled;
                    padapter->securitypriv.dot11PrivacyAlgrthm=_NO_PRIVACY_;
                    padapter->securitypriv.dot118021XGrpPrivacy=_NO_PRIVACY_;
                    padapter->securitypriv.dot11AuthAlgrthm= dot11AuthAlgrthm_Open; //open system
                    padapter->securitypriv.ndisauthtype=Ndis802_11AuthModeOpen;
                }

                break;
            }

        case WC_AUTH_80211_AUTH_ALG:

#if defined(CONFIG_ANDROID) || 1
            /*
             *  It's the starting point of a link layer connection using wpa_supplicant
             */
            if(check_fwstate(&padapter->mlmepriv, _FW_LINKED)) {
                LeaveAllPowerSaveMode(padapter);
                rtw_disassoc_cmd(padapter, 500, _FALSE);
                RTW_INFO("%s...call rtw_indicate_disconnect\n ",__FUNCTION__);
                rtw_indicate_disconnect(padapter, 0, _FALSE);
                rtw_free_assoc_resources_cmd(padapter, _TRUE, RTW_CMDF_WAIT_ACK);
            }
#endif
            ret = wpa_set_auth_algs(dev, (u32)iwcp->param2);
            break;

        case WC_AUTH_WPA_ENABLED:

            //if(param->value)
            //	padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_8021X; //802.1x
            //else
            //	padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_Open;//open system
            //_disassociate(priv);

            break;

        case WC_AUTH_RX_UNENCRYPTED_EAPOL:
            //ieee->ieee802_1x = param->value;
            break;

        case WC_AUTH_PRIVACY_INVOKED:
            //ieee->privacy_invoked = param->value;
            break;

#ifdef CONFIG_WAPI_SUPPORT
#ifndef CONFIG_IOCTL_CFG80211
        case IW_AUTH_WAPI_ENABLED:
            break;
#endif
#endif

        default:
            return -1;

    }
    return ret;
}

static int rtw_wx_set_enc_ext(struct net_device *dev, struct rtw_wc_param *iwcp) 
{
    char *alg_name;
    u32 param_len;
    struct ieee_param *param = NULL;
    struct rtw_wc_encode_ext *pext = (struct rtw_wc_encode_ext *)iwcp->wc_apps_data;
    int ret=0;

    param_len = sizeof(struct ieee_param) + pext->key_len;
    param = (struct ieee_param *)rtw_malloc(param_len);
    if (param == NULL)
        return -1;

    _rtw_memset(param, 0, param_len);

    param->cmd = IEEE_CMD_SET_ENCRYPTION;
    _rtw_memset(param->sta_addr, 0xff, ETH_ALEN);


    switch (pext->alg) {
        case WC_ENCODE_ALG_NONE:
            //todo: remove key 
            //remove = 1;	
            alg_name = "none";
            break;
        //case WC_ENCODE_ALG_WEP:
        //    alg_name = "WEP";
         //   break;
        case WC_ENCODE_ALG_TKIP:
            alg_name = "TKIP";
            break;
        case WC_ENCODE_ALG_CCMP:
            alg_name = "CCMP";
            break;
#ifdef CONFIG_WAPI_SUPPORT
#ifndef CONFIG_IOCTL_CFG80211
        case WC_ENCODE_ALG_SM4:
            alg_name= "SMS4";
            _rtw_memcpy(param->sta_addr, pext->addr.sa_data, ETH_ALEN);
            RTW_INFO("rtw_wx_set_enc_ext: SMS4 case \n");
            break;
#endif
#endif
        default:
			ret = -1;
			rtw_mfree((u8 *)param, param_len);
            return ret;
    }

    strncpy((char *)param->u.crypt.alg, alg_name, IEEE_CRYPT_ALG_NAME_LEN);

    if (pext->ext_flags & WC_ENCODE_EXT_SET_TX_KEY)
    {
        param->u.crypt.set_tx = 1;
    }

    /* cliW: WEP does not have group key
     * just not checking GROUP key setting 
     */
    if ((pext->alg != WC_ENCODE_ALG_WEP) &&
            (pext->ext_flags & WC_ENCODE_EXT_GROUP_KEY))
    {
        param->u.crypt.set_tx = 0;
    }

    param->u.crypt.idx = (iwcp->param1 &0x00FF) -1 ; //param1 should hold the key index 

    if (pext->ext_flags & WC_ENCODE_EXT_RX_SEQ_VALID)
    {
#ifdef CONFIG_WAPI_SUPPORT
#ifndef CONFIG_IOCTL_CFG80211
        if(pext->alg == IW_ENCODE_ALG_SM4)
            _rtw_memcpy(param->u.crypt.seq, pext->seq, 16);
        else
#endif
#endif
            _rtw_memcpy(param->u.crypt.seq, pext->seq, 8);
    }

    if(pext->key_len)
    {
        param->u.crypt.key_len = pext->key_len;
        //_rtw_memcpy(param + 1, pext + 1, pext->key_len);
        _rtw_memcpy(param->u.crypt.key, pext + 1, pext->key_len);
    }

    if (iwcp->param2 & WC_ENCODE_DISABLED)
    {
        //todo: remove key 
        //remove = 1;
    }

    ret =  wpa_set_encryption(dev, param, param_len);

    if(param)
    {
        rtw_mfree((u8*)param, param_len);
    }

    return ret;
}


static int rtw_wx_get_nick(struct net_device *dev, struct rtw_wc_param *iwcp) 
{	
	//_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
	 //struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
	 //struct security_priv *psecuritypriv = &padapter->securitypriv;

	if(iwcp->wc_apps_data)
	{
		iwcp->param1= 14;
		_rtw_memcpy(iwcp->wc_apps_data, "<WIFI@REALTEK>", 14);
	}

	//rtw_signal_process(pid, SIGUSR1); //for test

	//dump debug info here	
/*
	u32 dot11AuthAlgrthm;		// 802.11 auth, could be open, shared, and 8021x
	u32 dot11PrivacyAlgrthm;	// This specify the privacy for shared auth. algorithm.
	u32 dot118021XGrpPrivacy;	// This specify the privacy algthm. used for Grp key 
	u32 ndisauthtype;
	u32 ndisencryptstatus;
*/

	//RTW_INFO("auth_alg=0x%x, enc_alg=0x%x, auth_type=0x%x, enc_type=0x%x\n", 
	//		psecuritypriv->dot11AuthAlgrthm, psecuritypriv->dot11PrivacyAlgrthm,
	//		psecuritypriv->ndisauthtype, psecuritypriv->ndisencryptstatus);
	
	//RTW_INFO("enc_alg=0x%x\n", psecuritypriv->dot11PrivacyAlgrthm);
	//RTW_INFO("auth_type=0x%x\n", psecuritypriv->ndisauthtype);
	//RTW_INFO("enc_type=0x%x\n", psecuritypriv->ndisencryptstatus);

#if 0
	RTW_INFO("dbg(0x210)=0x%x\n", rtw_read32(padapter, 0x210));
	RTW_INFO("dbg(0x608)=0x%x\n", rtw_read32(padapter, 0x608));
	RTW_INFO("dbg(0x280)=0x%x\n", rtw_read32(padapter, 0x280));
	RTW_INFO("dbg(0x284)=0x%x\n", rtw_read32(padapter, 0x284));
	RTW_INFO("dbg(0x288)=0x%x\n", rtw_read32(padapter, 0x288));
	
	RTW_INFO("dbg(0x664)=0x%x\n", rtw_read32(padapter, 0x664));


	RTW_INFO("\n");

	RTW_INFO("dbg(0x430)=0x%x\n", rtw_read32(padapter, 0x430));
	RTW_INFO("dbg(0x438)=0x%x\n", rtw_read32(padapter, 0x438));

	RTW_INFO("dbg(0x440)=0x%x\n", rtw_read32(padapter, 0x440));
	
	RTW_INFO("dbg(0x458)=0x%x\n", rtw_read32(padapter, 0x458));
	
	RTW_INFO("dbg(0x484)=0x%x\n", rtw_read32(padapter, 0x484));
	RTW_INFO("dbg(0x488)=0x%x\n", rtw_read32(padapter, 0x488));
	
	RTW_INFO("dbg(0x444)=0x%x\n", rtw_read32(padapter, 0x444));
	RTW_INFO("dbg(0x448)=0x%x\n", rtw_read32(padapter, 0x448));
	RTW_INFO("dbg(0x44c)=0x%x\n", rtw_read32(padapter, 0x44c));
	RTW_INFO("dbg(0x450)=0x%x\n", rtw_read32(padapter, 0x450));
#endif
	
	return 0;

}

static int rtw_wx_read32(struct net_device *dev, struct rtw_wc_param *iwcp)
{
    u32 addr  = iwcp->param2;
    u32 bytes = iwcp->param1;

    struct net_device *netdev = rtw_get_netdev(dev);
	_adapter *padapter = (_adapter *)rtw_netdev_priv(netdev);

    switch (bytes) {
        case 1:
            iwcp->param3 = rtw_read8(padapter, addr);
            //sprintf(iwcp->wc_apps_data, "0x%02X", data32); //out parameter
            break;
        case 2:
            iwcp->param3 = rtw_read16(padapter, addr);
            //sprintf(iwcp->wc_apps_data, "0x%04X", data32); //out parameter
            break;
        case 4:  
            iwcp->param3 = rtw_read32(padapter, addr); //out paramter
            //sprintf(iwcp->wc_apps_data, "0x%08X", data32);
            break;
		case 8:  //just for liteos debug,dump all reg
			mac_reg_dump(RTW_DBGDUMP, padapter);
			bb_reg_dump(RTW_DBGDUMP, padapter);
			rf_reg_dump(RTW_DBGDUMP, padapter);
            //iwcp->param3 = rtw_read32(padapter, addr); //out paramter
            //sprintf(iwcp->wc_apps_data, "0x%08X", data32);
            break;		
        default:
            RTW_INFO("%s: usage> read [bytes],[address(hex)]\n", __func__);
            return -EINVAL;
    }
    //RTW_INFO("%s: addr=0x%08X data=%x\n", __func__, addr, iwcp->param3);

    return 0;
}

static int rtw_wx_write32(struct net_device *dev, struct rtw_wc_param *iwcp)
{
	struct net_device *netdev = rtw_get_netdev(dev);
	_adapter *padapter = (_adapter *)rtw_netdev_priv(netdev);

	u32 addr   = iwcp->param3;  
	u32 data32 = iwcp->param2;
	u32 bytes = iwcp->param1;

	switch (bytes) {
		case 1:
			rtw_write8(padapter, addr, (u8)data32);
//			RTW_INFO("%s: addr=0x%08X data=0x%02X\n", __func__, addr, (u8)data32);
			break;
		case 2:
			rtw_write16(padapter, addr, (u16)data32);
//			RTW_INFO("%s: addr=0x%08X data=0x%04X\n", __func__, addr, (u16)data32);
			break;
		case 4:
			rtw_write32(padapter, addr, data32);
//			RTW_INFO("%s: addr=0x%08X data=0x%08X\n", __func__, addr, data32);
			break;
		default:
//			RTW_INFO("%s: usage> write [bytes],[address(hex)],[data(hex)]\n", __func__);
			return -EINVAL;
	}

	return 0;
}

static int rtw_wx_read_rf(struct net_device *dev, struct rtw_wc_param *iwcp)
{
    struct net_device *netdev = rtw_get_netdev(dev);
	_adapter *padapter = (_adapter *)rtw_netdev_priv(netdev);
    u32 path, addr, data32;


    path = iwcp->param1;
    addr = iwcp->param2;
    data32 = rtw_hal_read_rfreg(padapter, path, addr, 0xFFFFF);
    //	RTW_INFO("%s: path=%d addr=0x%02x data=0x%05x\n", __func__, path, addr, data32);
    /*
     * IMPORTANT!!
     * Only when wireless private ioctl is at odd order,
     * "extra" would be copied to user space.
     */
    iwcp->param3 = data32;
    return 0;
}

static int rtw_wx_write_rf(struct net_device *dev, struct rtw_wc_param *iwcp)
{
	struct net_device *netdev = rtw_get_netdev(dev);
	_adapter *padapter = (_adapter *)rtw_netdev_priv(netdev);
	u32 path, addr, data32;


	path = iwcp->param1;
	addr = iwcp->param2; 
	data32 = iwcp->param3;
//	RTW_INFO("%s: path=%d addr=0x%02x data=0x%05x\n", __func__, path, addr, data32);
	rtw_hal_write_rfreg(padapter, path, addr, 0xFFFFF, data32);

	return 0;
}

static int rtw_wx_priv_null(struct net_device *dev, struct rtw_wc_param *iwcp)
{
	return -1;
}

static int dummy(struct net_device *dev, struct rtw_wc_param *iwcp)
{
	//_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);	
	//struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);

	//RTW_INFO("cmd_code=%x, fwstate=0x%x\n", a->cmd, get_fwstate(pmlmepriv));
	
	return -1;
	
}
static int rtw_wx_write_mac(struct net_device *dev,struct rtw_wc_param *iwcp)
{
	_adapter *padapter;
	u8 mac[ETH_ALEN];
	u32 i, j;
	u16 addr=0;
	u8* macaddr=(u8*)(iwcp->wc_apps_data);
	
	padapter = (_adapter *)rtw_netdev_priv(rtw_netdev[0]);
#if defined(CONFIG_RTL8188E)
	addr = EEPROM_MAC_ADDR_88ES;
#elif defined(CONFIG_RTL8188F)
	addr = EEPROM_MAC_ADDR_8188FS;
#elif defined(CONFIG_RTL8723D)
	addr = EEPROM_MAC_ADDR_8723DS;
#elif defined(CONFIG_RTL8821C)
	addr = EEPROM_MAC_ADDR_8821CS;
#else
	return -1;
#endif
	
//	sscanf(wrqu->pointer, MAC_FMT, mac, mac+1, mac+2, mac+3, mac+4, mac+5);
	for (i=0, j=0; i<ETH_ALEN; i++, j+=2){
		mac[i] = key_2char2num(macaddr[j], macaddr[j+1]);
	}
	if(rtw_efuse_map_write(padapter, addr, ETH_ALEN, mac) == _FAIL){
		RTW_INFO("write mac address error!\r\n");
		return -1;
	}
	_rtw_memcpy(rtw_netdev[0]->dev_addr,mac,ETH_ALEN);
	_rtw_memcpy(padapter->mac_addr, mac, ETH_ALEN);
	RTW_INFO("write mac address success, please reset wifi driver!\r\n");
	return 0;
}

static int rtw_wx_set_channel_plan(struct net_device *dev, struct rtw_wc_param *iwcp)
{
	struct net_device *netdev = rtw_get_netdev(dev);
	_adapter *padapter = (_adapter *)rtw_netdev_priv(netdev);
	struct registry_priv *pregistrypriv = &padapter->registrypriv;
	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
	extern int rtw_channel_plan;
	u8 channel_plan_req = (u8)iwcp->param1;

    if (pmlmepriv);
    if (pregistrypriv);

#if 0
    rtw_channel_plan = (int)wrqu->data.pointer;
    pregistrypriv->channel_plan = rtw_channel_plan;
    pmlmepriv->ChannelPlan = pregistrypriv->channel_plan;
#endif

	if( _SUCCESS == rtw_set_chplan_cmd(padapter, 1, channel_plan_req, 0) ) {
		RTW_INFO("%s set channel_plan = 0x%02X\n", __func__, channel_plan_req);
	} else 
		return -EPERM;

	return 0;
}

static int rtw_wx_set_mtk_wps_probe_ie(struct net_device *dev, struct rtw_wc_param *iwcp)
{
#ifdef CONFIG_PLATFORM_MT53XX
	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);
	struct mlme_priv *pmlmepriv = &padapter->mlmepriv;

	RTW_INFO("WLAN IOCTL: cmd_code=%x, fwstate=0x%x\n", a->cmd, get_fwstate(pmlmepriv));
#endif
	return 0;
}

static int rtw_wx_get_sensitivity(struct net_device *dev,struct rtw_wc_param *iwcp)
{
#ifdef CONFIG_PLATFORM_MT53XX
	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);

	//	Modified by Albert 20110914
	//	This is in dbm format for MTK platform.
	wrqu->qual.level = padapter->recvpriv.rssi;
	RTW_INFO(" level = %u\n",  wrqu->qual.level );
#endif
	return 0;
}

static int rtw_wx_set_mtk_wps_ie(struct net_device *dev, struct rtw_wc_param *iwcp)
{
#ifdef CONFIG_PLATFORM_MT53XX
	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);

	return rtw_set_wpa_ie(padapter, wrqu->data.pointer, wrqu->data.length);
#else
	return 0;
#endif
}

/*
typedef int (*iw_handler)(struct net_device *dev, struct iw_request_info *info,
			  union iwreq_data *wrqu, char *extra);
*/
/*
 *	For all data larger than 16 octets, we need to use a
 *	pointer to memory allocated in user space.
 */
static  int rtw_drvext_hdl(struct net_device *dev, struct rtw_wc_param *iwcp)
{

 #if 0
struct	iw_point
{
  void __user	*pointer;	/* Pointer to the data  (in user space) */
  __u16		length;		/* number of fields or size in bytes */
  __u16		flags;		/* Optional params */
};
 #endif

#ifdef CONFIG_DRVEXT_MODULE
	u8 res;
	struct drvext_handler *phandler;	
	struct drvext_oidparam *poidparam;		
	int ret;
	u16 len;
	u8 *pparmbuf, bset;
	_adapter *padapter = (_adapter *)rtw_netdev_priv(dev);

	if( (!iwcp->param2) || (!iwcp->wc_apps_data)){
		ret = -EINVAL;
		goto _rtw_drvext_hdl_exit;
	}
	
	
	bset = (u8)(iwcp->param1 &0xFFFF);
	len = iwcp->param2;
	pparmbuf = (u8*)rtw_malloc(len);
	if (pparmbuf == NULL){
		ret = -ENOMEM;
		goto _rtw_drvext_hdl_exit;
	}
	
	if(bset)//set info
	{
		if (copy_from_user(pparmbuf, iwcp->wc_apps_data,len)) {
			rtw_mfree(pparmbuf, len);
			ret = -EFAULT;
			goto _rtw_drvext_hdl_exit;
		}		
	}
	else//query info
	{
	
	}

	
	//
	poidparam = (struct drvext_oidparam *)pparmbuf;	
	
	RTW_INFO("drvext set oid subcode [%d], len[%d], InformationBufferLength[%d]\r\n", poidparam->subcode, poidparam->len, len);

	//check subcode	
	if ( poidparam->subcode >= MAX_DRVEXT_HANDLERS)
	{
		RTW_INFO("no matching drvext handlers\r\n");		
		ret = -EINVAL;
		goto _rtw_drvext_hdl_exit;
	}


	if ( poidparam->subcode >= MAX_DRVEXT_OID_SUBCODES)
	{
		RTW_INFO("no matching drvext subcodes\r\n");		
		ret = -EINVAL;
		goto _rtw_drvext_hdl_exit;
	}


	phandler = drvextoidhandlers + poidparam->subcode;

	if (poidparam->len != phandler->parmsize)
	{
		RTW_INFO("no matching drvext param size %d vs %d\r\n", poidparam->len , phandler->parmsize));		
		ret = -EINVAL;		
		goto _rtw_drvext_hdl_exit;
	}


	res = phandler->handler(&padapter->drvextpriv, bset, poidparam->data);

	if(res==0)
	{
		ret = 0;
			
		if (bset == 0x00) {//query info
			//_rtw_memcpy(p->pointer, pparmbuf, len);
			if (copy_to_user(iwcp->wc_apps_data, pparmbuf, len))
				ret = -EFAULT;
		}		
	}		
	else
		ret = -EFAULT;

	
_rtw_drvext_hdl_exit:	
	
	return ret;	
	
#endif

	return 0;

}

#ifdef MP_IOCTL_HDL
static void rtw_dbg_mode_hdl(_adapter *padapter, u32 id, u8 *pdata, u32 len)
{
	pRW_Reg 	RegRWStruct;
	struct rf_reg_param *prfreg;
	u8 path;
	u8 offset;
	u32 value;

	RTW_INFO("%s\n", __FUNCTION__);

	switch(id)
	{
		case GEN_MP_IOCTL_SUBCODE(MP_START):
			RTW_INFO("871x_driver is only for normal mode, can't enter mp mode\n");
			break;
		case GEN_MP_IOCTL_SUBCODE(READ_REG):
			RegRWStruct = (pRW_Reg)pdata;
			switch (RegRWStruct->width)
			{
				case 1:
					RegRWStruct->value = rtw_read8(padapter, RegRWStruct->offset);
					break;
				case 2:
					RegRWStruct->value = rtw_read16(padapter, RegRWStruct->offset);
					break;
				case 4:
					RegRWStruct->value = rtw_read32(padapter, RegRWStruct->offset);
					break;
				default:
					break;
			}
		
			break;
		case GEN_MP_IOCTL_SUBCODE(WRITE_REG):
			RegRWStruct = (pRW_Reg)pdata;
			switch (RegRWStruct->width)
			{
				case 1:
					rtw_write8(padapter, RegRWStruct->offset, (u8)RegRWStruct->value);
					break;
				case 2:
					rtw_write16(padapter, RegRWStruct->offset, (u16)RegRWStruct->value);
					break;
				case 4:
					rtw_write32(padapter, RegRWStruct->offset, (u32)RegRWStruct->value);
					break;
				default:					
				break;
			}
				
			break;
		case GEN_MP_IOCTL_SUBCODE(READ_RF_REG):

			prfreg = (struct rf_reg_param *)pdata;

			path = (u8)prfreg->path;		
			offset = (u8)prfreg->offset;	

			value = rtw_hal_read_rfreg(padapter, path, offset, 0xffffffff);

			prfreg->value = value;

			break;			
		case GEN_MP_IOCTL_SUBCODE(WRITE_RF_REG):

			prfreg = (struct rf_reg_param *)pdata;

			path = (u8)prfreg->path;
			offset = (u8)prfreg->offset;	
			value = prfreg->value;

			rtw_hal_write_rfreg(padapter, path, offset, 0xffffffff, value);
			
			break;			
                case GEN_MP_IOCTL_SUBCODE(TRIGGER_GPIO):
			RTW_INFO("==> trigger gpio 0\n");
			rtw_hal_set_hwreg(padapter, HW_VAR_TRIGGER_GPIO_0, 0);
			break;	
#ifdef CONFIG_BT_COEXIST
		case GEN_MP_IOCTL_SUBCODE(SET_DM_BT):			
			RTW_INFO("==> set dm_bt_coexist:%x\n",*(u8 *)pdata);
			rtw_hal_set_hwreg(padapter, HW_VAR_BT_SET_COEXIST, pdata);
			break;
		case GEN_MP_IOCTL_SUBCODE(DEL_BA):
			RTW_INFO("==> delete ba:%x\n",*(u8 *)pdata);
			rtw_hal_set_hwreg(padapter, HW_VAR_BT_ISSUE_DELBA, pdata);
			break;
#endif
#ifdef DBG_CONFIG_ERROR_DETECT
		case GEN_MP_IOCTL_SUBCODE(GET_WIFI_STATUS):							
			*pdata = rtw_hal_sreset_get_wifi_status(padapter);                   
			break;
#endif
	
		default:
			break;
	}
	
}

static int rtw_mp_ioctl_hdl(struct net_device *dev, struct rtw_wc_param *iwcp)
{
	int ret = 0;
	u32 BytesRead, BytesWritten, BytesNeeded;
	struct oid_par_priv	oid_par;
	struct mp_ioctl_handler	*phandler;
	struct mp_ioctl_param	*poidparam;
	uint status=0;
	u16 len;
	u8 *pparmbuf = NULL, bset;
	struct net_device *netdev = rtw_get_netdev(dev);
	_adapter *padapter = (_adapter *)rtw_netdev_priv(netdev);

	//RTW_INFO("+rtw_mp_ioctl_hdl\n");

	//mutex_lock(&ioctl_mutex);

	if ((!iwcp->param2) || (!iwcp->wc_apps_data)) { //length and data pointer
		ret = -EINVAL;
		goto _rtw_mp_ioctl_hdl_exit;
	}

	pparmbuf = NULL;
	bset = (u8)(iwcp->param1 & 0xFFFF); //flags
	len = iwcp->param2;                 //length
	pparmbuf = (u8*)rtw_malloc(len);
	if (pparmbuf == NULL){
		ret = -ENOMEM;
		goto _rtw_mp_ioctl_hdl_exit;
	}

	if (copy_from_user(pparmbuf,iwcp->wc_apps_data , len)) { //input
		ret = -EFAULT;
		goto _rtw_mp_ioctl_hdl_exit;
	}

	poidparam = (struct mp_ioctl_param *)pparmbuf;
	RTW_INFO("rtw_mp_ioctl_hdl: subcode [%d], len[%d], buffer_len[%d]\r\n", poidparam->subcode, poidparam->len, len);

	if (poidparam->subcode >= MAX_MP_IOCTL_SUBCODE) {
		RTW_INFO("no matching drvext subcodes\r\n");
		ret = -EINVAL;
		goto _rtw_mp_ioctl_hdl_exit;
	}

	//RTW_INFO("%s: %d\n", __func__, poidparam->subcode);
#ifdef CONFIG_MP_INCLUDED 
    if (padapter->registrypriv.mp_mode == 1)
    {	
        phandler = mp_ioctl_hdl + poidparam->subcode;

        if ((phandler->paramsize != 0) && (poidparam->len < phandler->paramsize))
        {
            RTW_INFO("no matching drvext param size %d vs %d\r\n", poidparam->len, phandler->paramsize);
            ret = -EINVAL;
            goto _rtw_mp_ioctl_hdl_exit;
        }

        if (phandler->handler)
        {
            oid_par.adapter_context = padapter;
            oid_par.oid = phandler->oid;
            oid_par.information_buf = poidparam->data;
            oid_par.information_buf_len = poidparam->len;
            oid_par.dbg = 0;

            BytesWritten = 0;
            BytesNeeded = 0;

            if (bset) {
                oid_par.bytes_rw = &BytesRead;
                oid_par.bytes_needed = &BytesNeeded;
                oid_par.type_of_oid = SET_OID;
            } else {
                oid_par.bytes_rw = &BytesWritten;
                oid_par.bytes_needed = &BytesNeeded;
                oid_par.type_of_oid = QUERY_OID;
            }

            status = phandler->handler(&oid_par);

            //todo:check status, BytesNeeded, etc.
        }
        else {
            RTW_INFO("rtw_mp_ioctl_hdl(): err!, subcode=%d, oid=%d, handler=%p\n", 
                    poidparam->subcode, phandler->oid, phandler->handler);
            ret = -EFAULT;
            goto _rtw_mp_ioctl_hdl_exit;
        }
    }
    else
#endif
{
	rtw_dbg_mode_hdl(padapter, poidparam->subcode, poidparam->data, poidparam->len);
}

	if (bset == 0x00) {//query info
		if (copy_to_user(iwcp->wc_apps_data, pparmbuf, len))
			ret = -EFAULT;
	}

	if (status) {
		ret = -EFAULT;
		goto _rtw_mp_ioctl_hdl_exit;
	}

_rtw_mp_ioctl_hdl_exit:

	if (pparmbuf)
		rtw_mfree(pparmbuf, len);

	//mutex_unlock(&ioctl_mutex);

	return ret;
}
#endif

static int rtw_get_ap_info(struct net_device *dev, struct rtw_wc_param *iwcp)
{
	int bssid_match, ret = 0;
	u32 cnt=0, wpa_ielen;
	_irqL	irqL;
	_list	*plist, *phead;
	unsigned char *pbuf;
	u8 bssid[ETH_ALEN];
	char data[32];
	struct wlan_network *pnetwork = NULL;
	struct net_device *netdev = rtw_get_netdev(dev);
	_adapter *padapter = (_adapter *)rtw_netdev_priv(netdev);	
	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);	
	_queue *queue = &(pmlmepriv->scanned_queue);

	RTW_INFO("+rtw_get_aplist_info\n");

    if (bssid_match);

	if(rtw_is_drv_stopped(padapter) || (iwcp->wc_apps_data == NULL))
	{                
		ret= -EINVAL;
		goto exit;
	}		
  
 	while((check_fwstate(pmlmepriv, (_FW_UNDER_SURVEY|_FW_UNDER_LINKING))) == _TRUE)
	{	
		rtw_msleep_os(30);
		cnt++;
		if(cnt > 100)
			break;
	}
	

	if(iwcp->param1 >= 32) //length
    {
        if(copy_from_user(data, iwcp->wc_apps_data, 32)) //data
        {
            ret= -EINVAL;
            goto exit;
        }
    }	
	else
    {
        ret= -EINVAL;
        goto exit;
    }	

	_enter_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
	
	phead = get_list_head(queue);
	plist = get_next(phead);
       
	while(1)
	{
		if (rtw_end_of_queue_search(phead,plist)== _TRUE)
			break;


		pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);

		//if(hwaddr_aton_i(pdata->pointer, bssid)) 
		if(hwaddr_aton_i(data, bssid)) 
		{			
			RTW_INFO("Invalid BSSID '%s'.\n", (u8*)data);
			_exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);
			return -EINVAL;
		}		
		
	
		if(_rtw_memcmp(bssid, pnetwork->network.MacAddress, ETH_ALEN) == _TRUE)//BSSID match, then check if supporting wpa/wpa2
		{
			RTW_INFO("BSSID:" MAC_FMT "\n", MAC_ARG(bssid));
			
			pbuf = rtw_get_wpa_ie(&pnetwork->network.IEs[12], (int *)&wpa_ielen, pnetwork->network.IELength-12);				
			if(pbuf && (wpa_ielen>0))
			{
				iwcp->param2 = 1; //flags
				break;
			}

			pbuf = rtw_get_wpa2_ie(&pnetwork->network.IEs[12], (int *)&wpa_ielen, pnetwork->network.IELength-12);
			if(pbuf && (wpa_ielen>0))
			{
				iwcp->param2 = 2; //flags
				break;
			}
			
		}

		plist = get_next(plist);		
	
	}        

	_exit_critical_bh(&(pmlmepriv->scanned_queue.lock), &irqL);

	if(iwcp->param1 >= 34) //length
	{
		//if(copy_to_user((u8*)iwcp->wc_apps_data + 32, (u8*)&iwcp->param2, 1))
		{
			ret= -EINVAL;
			goto exit;
		}
	}	
	
exit:
	
	return ret;
		
}

static int rtw_set_pid(struct net_device *dev, struct rtw_wc_param *iwcp)
{
	
	int ret = 0;	
	struct net_device *netdev = rtw_get_netdev(dev);
	_adapter *padapter = (_adapter *)rtw_netdev_priv(netdev);	
	int *pdata = (int *)iwcp->wc_apps_data;
	int selector;

	if(rtw_is_drv_stopped(padapter) || (pdata==NULL))
	{                
		ret= -EINVAL;
		goto exit;
	}		
  
	selector = *pdata;
	if(selector < 3 && selector >=0) {
		padapter->pid[selector] = *(pdata+1);
#ifdef CONFIG_GLOBAL_UI_PID
        ui_pid[selector] = *(pdata+1);
#endif
        RTW_INFO("%s set pid[%d]=%d\n", __FUNCTION__, selector ,padapter->pid[selector]);
    }
	else
        RTW_INFO("%s selector %d error\n", __FUNCTION__, selector);

exit:
	return ret;
}

static int rtw_wps_start(struct net_device *dev,struct rtw_wc_param *iwcp)
{

    int ret = 0;	
    struct net_device *netdev = rtw_get_netdev(dev);
	_adapter *padapter = (_adapter *)rtw_netdev_priv(netdev);	
    u32   u32wps_start = iwcp->param1;
    unsigned int uintRet = 0;

    if(rtw_is_drv_stopped(padapter) || (iwcp->wc_apps_data == NULL))
    {                
        ret= -EINVAL;
        goto exit;
    }		

    RTW_INFO( "[%s] wps_start = %d\n", __FUNCTION__, u32wps_start );

    if ( u32wps_start == 1 ) // WPS Start
    {
        rtw_led_control(padapter, LED_CTL_START_WPS);
    }
    else if ( u32wps_start == 2 ) // WPS Stop because of wps success
    {
        rtw_led_control(padapter, LED_CTL_STOP_WPS);
    }
    else if ( u32wps_start == 3 ) // WPS Stop because of wps fail
    {
        rtw_led_control(padapter, LED_CTL_STOP_WPS_FAIL);
    }

#ifdef CONFIG_INTEL_WIDI
    process_intel_widi_wps_status(padapter, u32wps_start);
#endif //CONFIG_INTEL_WIDI

exit:

    return ret;
}

static int rtw_conn_get_status(struct net_device *dev, struct rtw_wc_param *iwcp)
{
	RTW_INFO("Enter rtw_conn_get_status \n");
}

static int rtw_get_own_mac(struct net_device *dev, struct rtw_wc_param *iwcp)
{
	struct net_device *netdev = rtw_get_netdev(dev);
	_adapter *padapter = (_adapter *)rtw_netdev_priv(netdev);
    memcpy(iwcp->wc_apps_data, &padapter->mac_addr,ETH_ALEN);
	RTW_INFO("rtw_get_own_mac:\n");
	RTW_INFO("%x:%x:%x:%x:%x:%x\n", padapter->mac_addr[0], padapter->mac_addr[1], 
									padapter->mac_addr[2], padapter->mac_addr[3],
									padapter->mac_addr[4], padapter->mac_addr[5]);
	return 0;
}

static int rtw_dbg_port(struct net_device *dev, struct rtw_wc_param *iwcp)
{
	RTW_INFO("Enter rtw_dbg_port \n");
}


#define TOLOWER(x) ((x) | 0x20)

unsigned long simple_strtoul(const char *cp, char **endp, unsigned int base)  
{  
    unsigned long result = 0;  
   
    if (base == 16 && cp[0] == '0' && TOLOWER(cp[1]) == 'x')  
        cp += 2;  
  
    while ( ((*cp)>='0' && (*cp)<='9') ||  ((*cp)>='a' && (*cp)<='f') || ((*cp)>='A' && (*cp)<='F') ) {  
        unsigned int value;  
  
        value = ((*cp)>='0' && (*cp)<='9') ? *cp - '0' : TOLOWER(*cp) - 'a' + 10;  
        if (value >= base)  
            break;  
        result = result * base + value;  
        cp++;  
    }  
  
    if (endp)  
        *endp = (char *)cp;  
    return result;  
}



static int rtw_mp_efuse_get(struct net_device *dev,
			    struct iw_request_info *info,
			    union iwreq_data *wdata, char *extra)
{
	PADAPTER padapter = rtw_netdev_priv(dev);
	HAL_DATA_TYPE	*pHalData = GET_HAL_DATA(padapter);

	PEFUSE_HAL pEfuseHal;
	struct iw_point *wrqu;

	u8	*PROMContent = pHalData->efuse_eeprom_data;
	u8 ips_mode = IPS_NUM; /* init invalid value */
	u8 lps_mode = PS_MODE_NUM; /* init invalid value */
	struct pwrctrl_priv *pwrctrlpriv ;
	u8 *data = NULL;
	u8 *rawdata = NULL;
	char *pch, *ptmp, *token, *tmp[3] = {0x00, 0x00, 0x00};
	u16 i = 0, j = 0, mapLen = 0, addr = 0, cnts = 0;
	u16 max_available_len = 0, raw_cursize = 0, raw_maxsize = 0;
	u16 mask_len;
	u8 mask_buf[64] = "";
	int err;
	char *pextra = NULL;
#ifdef CONFIG_IOL
	u8 org_fw_iol = padapter->registrypriv.fw_iol;/* 0:Disable, 1:enable, 2:by usb speed */
#endif

	wrqu = (struct iw_point *)wdata;
	pwrctrlpriv = adapter_to_pwrctl(padapter);
	pEfuseHal = &pHalData->EfuseHal;

	err = 0;
	data = rtw_zmalloc(EFUSE_BT_MAX_MAP_LEN);
	if (data == NULL) {
		err = -ENOMEM;
		goto exit;
	}
	rawdata = rtw_zmalloc(EFUSE_BT_MAX_MAP_LEN);
	if (rawdata == NULL) {
		err = -ENOMEM;
		goto exit;
	}

	if (copy_from_user(extra, wrqu->pointer, wrqu->length)) {
		err = -EFAULT;
		goto exit;
	}

	*(extra + wrqu->length) = '\0';

#ifdef CONFIG_LPS
	lps_mode = pwrctrlpriv->power_mgnt;/* keep org value */
	rtw_pm_set_lps(padapter, PS_MODE_ACTIVE);
#endif

#ifdef CONFIG_IPS
	ips_mode = pwrctrlpriv->ips_mode;/* keep org value */
	rtw_pm_set_ips(padapter, IPS_NONE);
#endif

	pch = extra;
	RTW_INFO("%s: in=%s\n", __FUNCTION__, extra);

	i = 0;
	/* mac 16 "00e04c871200" rmap,00,2 */
	while ((token = strsep(&pch, ",")) != NULL) {
		if (i > 2)
			break;
		tmp[i] = token;
		i++;
	}
#ifdef CONFIG_IOL
	padapter->registrypriv.fw_iol = 0;/* 0:Disable, 1:enable, 2:by usb speed */
#endif

	if (strcmp(tmp[0], "status") == 0) {
		sprintf(extra, "Load File efuse=%s,Load File MAC=%s"
			, pHalData->efuse_file_status == EFUSE_FILE_FAILED ? "FAIL" : "OK"
			, pHalData->macaddr_file_status == MACADDR_FILE_FAILED ? "FAIL" : "OK"
		       );
		goto exit;
	} else if (strcmp(tmp[0], "drvmap") == 0) {
		static u8 drvmaporder = 0;
		u8 *efuse;
		u32 shift, cnt;
		u32 blksz = 0x200; /* The size of one time show, default 512 */
		EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_MAP_LEN, (void *)&mapLen, _FALSE);

		efuse = pHalData->efuse_eeprom_data;

		shift = blksz * drvmaporder;
		efuse += shift;
		cnt = mapLen - shift;

		if (cnt > blksz) {
			cnt = blksz;
			drvmaporder++;
		} else
			drvmaporder = 0;

		sprintf(extra, "\n");
		for (i = 0; i < cnt; i += 16) {
			pextra = extra + strlen(extra);
			pextra += sprintf(pextra, "0x%02x\t", shift + i);
			for (j = 0; j < 8; j++)
				pextra += sprintf(pextra, "%02X ", efuse[i + j]);
			pextra += sprintf(pextra, "\t");
			for (; j < 16; j++)
				pextra += sprintf(pextra, "%02X ", efuse[i + j]);
			pextra += sprintf(pextra, "\n");
		}
		if ((shift + cnt) < mapLen)
			pextra += sprintf(pextra, "\t...more (left:%d/%d)\n", mapLen-(shift + cnt), mapLen);

	} else if (strcmp(tmp[0], "realmap") == 0) {
		static u8 order = 0;
		u8 *efuse;
		u32 shift, cnt;
		u32 blksz = 0x200; /* The size of one time show, default 512 */

		EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_MAP_LEN , (void *)&mapLen, _FALSE);
		efuse = pEfuseHal->fakeEfuseInitMap;
		if (rtw_efuse_mask_map_read(padapter, 0, mapLen, efuse) == _FAIL) {
			RTW_INFO("%s: read realmap Fail!!\n", __FUNCTION__);
			err = -EFAULT;
			goto exit;
		}

#if 0
		RTW_INFO("OFFSET\tVALUE(hex)\n");
		for (i = 0; i < mapLen; i += 16) {
			RTW_INFO("0x%02x\t", i);
			for (j = 0; j < 8; j++)
				RTW_INFO("%02X ", efuse[i + j]);
			RTW_INFO("\t");
			for (; j < 16; j++)
				RTW_INFO("%02X ", efuse[i + j]);
			RTW_INFO("\n");
		}
		RTW_INFO("\n");
#endif

		shift = blksz * order;
		efuse += shift;
		cnt = mapLen - shift;
		if (cnt > blksz) {
			cnt = blksz;
			order++;
		} else
			order = 0;

		sprintf(extra, "\n");
		for (i = 0; i < cnt; i += 16) {
			pextra = extra + strlen(extra);
			pextra += sprintf(pextra, "0x%02x\t", shift + i);
			for (j = 0; j < 8; j++)
				pextra += sprintf(pextra, "%02X ", efuse[i + j]);
			pextra += sprintf(pextra, "\t");
			for (; j < 16; j++)
				pextra += sprintf(pextra, "%02X ", efuse[i + j]);
			pextra += sprintf(pextra, "\n");
		}
		if ((shift + cnt) < mapLen)
			pextra += sprintf(pextra, "\t...more (left:%d/%d)\n", mapLen-(shift + cnt), mapLen);
	} else if (strcmp(tmp[0], "rmap") == 0) {
		if ((tmp[1] == NULL) || (tmp[2] == NULL)) {
			RTW_INFO("%s: rmap Fail!! Parameters error!\n", __FUNCTION__);
			err = -EINVAL;
			goto exit;
		}

		RTW_INFO("%s: tmp[1]=%s\n", __FUNCTION__, tmp[1]);
		RTW_INFO("%s: tmp[2]=%s\n", __FUNCTION__, tmp[2]);
		
		/* rmap addr cnts */
		addr = simple_strtoul(tmp[1], &ptmp, 16);
		RTW_INFO("%s: addr=0x%x\n", __FUNCTION__, addr);

		cnts = simple_strtoul(tmp[2], &ptmp, 10);
		if (cnts == 0) {
			RTW_INFO("%s: rmap Fail!! cnts error!\n", __FUNCTION__);
			err = -EINVAL;
			goto exit;
		}
		RTW_INFO("%s: cnts=%d\n", __FUNCTION__, cnts);


		EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_MAP_LEN , (PVOID)&max_available_len, _FALSE);
		if ((addr + cnts) > max_available_len) {
			RTW_INFO("%s: addr(0x%X)+cnts(%d) parameter error!\n", __FUNCTION__, addr, cnts);
			err = -EINVAL;
			goto exit;
		}

		if (rtw_efuse_mask_map_read(padapter, addr, cnts, data) == _FAIL) {
			RTW_INFO("%s: rtw_efuse_mask_map_read error!\n", __func__);
			err = -EFAULT;
			goto exit;
		}

		*extra = 0;		
		pextra = extra;
		for (i = 0; i < cnts; i++) {
			if((i)%16 == 0) {
				pextra += sprintf(pextra, "\n");
			}
			pextra += sprintf(pextra, "%02X ", data[i]);
		}

	} else if (strcmp(tmp[0], "realraw") == 0) {
		static u8 raw_order = 0;
		u32 shift, cnt;
		u32 blksz = 0x200; /* The size of one time show, default 512 */

		addr = 0;
		EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_REAL_CONTENT_LEN , (PVOID)&mapLen, _FALSE);
		RTW_INFO("Real content len = %d\n",mapLen );

		if (rtw_efuse_access(padapter, _FALSE, addr, mapLen, rawdata) == _FAIL) {
			RTW_INFO("%s: rtw_efuse_access Fail!!\n", __func__);
			err = -EFAULT;
			goto exit;
		}

		_rtw_memset(extra, '\0', strlen(extra));

		shift = blksz * raw_order;
		rawdata += shift;
		cnt = mapLen - shift;
		if (cnt > blksz) {
			cnt = blksz;
			raw_order++;
		} else
			raw_order = 0;

		sprintf(extra, "\n");
		for (i = 0; i < cnt; i += 16) {
			pextra = extra + strlen(extra);
			pextra += sprintf(pextra, "0x%02x\t", shift + i);
			for (j = 0; j < 8; j++)
				pextra += sprintf(pextra, "%02X ", rawdata[i + j]);
			pextra += sprintf(pextra, "\t");
			for (; j < 16; j++)
				pextra += sprintf(pextra, "%02X ", rawdata[i + j]);
			pextra += sprintf(pextra, "\n");
		}
		if ((shift + cnt) < mapLen)
			pextra += sprintf(pextra, "\t...more (left:%d/%d)\n", mapLen-(shift + cnt), mapLen);

	} 
	else
		sprintf(extra, "Command not found!");

exit:
	if (data)
		rtw_mfree(data, EFUSE_BT_MAX_MAP_LEN);
	if (rawdata)
		rtw_mfree(rawdata, EFUSE_BT_MAX_MAP_LEN);
	if (!err)
		wrqu->length = strlen(extra);

	if (padapter->registrypriv.mp_mode == 0) {
#ifdef CONFIG_IPS
		rtw_pm_set_ips(padapter, ips_mode);
#endif /* CONFIG_IPS */

#ifdef CONFIG_LPS
		rtw_pm_set_lps(padapter, lps_mode);
#endif /* CONFIG_LPS */
	}

#ifdef CONFIG_IOL
	padapter->registrypriv.fw_iol = org_fw_iol;/* 0:Disable, 1:enable, 2:by usb speed */
#endif
	return err;
}

static int rtw_mp_efuse_set(struct net_device *dev,
			    struct iw_request_info *info,
			    union iwreq_data *wdata, char *extra)
{
#ifdef CONFIG_MP_INCLUDED

	struct iw_point *wrqu;
	PADAPTER padapter;
	struct pwrctrl_priv *pwrctrlpriv ;
	PHAL_DATA_TYPE pHalData;
	PEFUSE_HAL pEfuseHal;
	struct hal_ops *pHalFunc;
	struct mp_priv *pmp_priv;

	u8 ips_mode = IPS_NUM; /* init invalid value */
	u8 lps_mode = PS_MODE_NUM; /* init invalid value */
	u32 i = 0, j = 0, jj, kk;
	u8 *setdata = NULL;
	u8 *ShadowMapBT = NULL;
	u8 *ShadowMapWiFi = NULL;
	u8 *setrawdata = NULL;
	char *pch, *ptmp, *token, *tmp[3] = {0x00, 0x00, 0x00};
	u16 addr = 0xFF, cnts = 0, BTStatus = 0 , max_available_len = 0;
	u16 wifimaplen;
	int err;

	wrqu = (struct iw_point *)wdata;
	padapter = rtw_netdev_priv(dev);
	pwrctrlpriv = adapter_to_pwrctl(padapter);
	pHalData = GET_HAL_DATA(padapter);
	pEfuseHal = &pHalData->EfuseHal;
	pHalFunc = &padapter->HalFunc;
	pmp_priv = &padapter->mppriv;

	err = 0;

	if (copy_from_user(extra, wrqu->pointer, wrqu->length))
		return -EFAULT;

	*(extra + wrqu->length) = '\0';

	EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_MAP_LEN , (void *)&wifimaplen, _FALSE);

	setdata = rtw_zmalloc(1024);
	if (setdata == NULL) {
		err = -ENOMEM;
		goto exit;
	}
	ShadowMapBT = rtw_malloc(EFUSE_BT_MAX_MAP_LEN);
	if (ShadowMapBT == NULL) {
		err = -ENOMEM;
		goto exit;
	}
	ShadowMapWiFi = rtw_malloc(wifimaplen);
	if (ShadowMapWiFi == NULL) {
		err = -ENOMEM;
		goto exit;
	}
	setrawdata = rtw_malloc(EFUSE_MAX_SIZE);
	if (setrawdata == NULL) {
		err = -ENOMEM;
		goto exit;
	}

#ifdef CONFIG_LPS
	lps_mode = pwrctrlpriv->power_mgnt;/* keep org value */
	rtw_pm_set_lps(padapter, PS_MODE_ACTIVE);
#endif

#ifdef CONFIG_IPS
	ips_mode = pwrctrlpriv->ips_mode;/* keep org value */
	rtw_pm_set_ips(padapter, IPS_NONE);
#endif

	pch = extra;
	RTW_INFO("%s: in=%s\n", __FUNCTION__, extra);

	i = 0;
	while ((token = strsep(&pch, ",")) != NULL) {
		if (i > 2)
			break;
		tmp[i] = token;
		i++;
	}

	/* tmp[0],[1],[2] */
	/* wmap,addr,00e04c871200 */
	if (strcmp(tmp[0], "wmap") == 0) {
		if ((tmp[1] == NULL) || (tmp[2] == NULL)) {
			err = -EINVAL;
			goto exit;
		}

#ifndef RTW_HALMAC
		/* unknown bug workaround, need to fix later */
		addr = 0x1ff;
		rtw_write8(padapter, EFUSE_CTRL + 1, (addr & 0xff));
		rtw_msleep_os(10);
		rtw_write8(padapter, EFUSE_CTRL + 2, ((addr >> 8) & 0x03));
		rtw_msleep_os(10);
		rtw_write8(padapter, EFUSE_CTRL + 3, 0x72);
		rtw_msleep_os(10);
		rtw_read8(padapter, EFUSE_CTRL);
#endif /* RTW_HALMAC */


		addr = simple_strtoul(tmp[1], &ptmp, 16);
		addr &= 0xFFF;

		cnts = strlen(tmp[2]);
		if (cnts % 2) {
			err = -EINVAL;
			goto exit;
		}
		cnts /= 2;
		if (cnts == 0) {
			err = -EINVAL;
			goto exit;
		}

		RTW_INFO("%s: addr=0x%X\n", __FUNCTION__, addr);
		RTW_INFO("%s: cnts=%d\n", __FUNCTION__, cnts);
		RTW_INFO("%s: map data=%s\n", __FUNCTION__, tmp[2]);

		for (jj = 0, kk = 0; jj < cnts; jj++, kk += 2)
			setdata[jj] = key_2char2num(tmp[2][kk], tmp[2][kk + 1]);

		EFUSE_GetEfuseDefinition(padapter, EFUSE_WIFI, TYPE_EFUSE_MAP_LEN, (PVOID)&max_available_len, _FALSE);

		if ((addr + cnts) > max_available_len) {
			RTW_INFO("%s: addr(0x%X)+cnts(%d) parameter error!\n", __FUNCTION__, addr, cnts);
			err = -EFAULT;
			goto exit;
		}

		if (rtw_efuse_map_write(padapter, addr, cnts, setdata) == _FAIL) {
			RTW_INFO("%s: rtw_efuse_map_write error!!\n", __FUNCTION__);
			err = -EFAULT;
			goto exit;
		}
		*extra = 0;
		RTW_INFO("%s: after rtw_efuse_map_write to _rtw_memcmp\n", __func__);
		if (rtw_efuse_mask_map_read(padapter, addr, cnts, ShadowMapWiFi) == _SUCCESS) {
			if (_rtw_memcmp((void *)ShadowMapWiFi , (void *)setdata, cnts)) {
				RTW_INFO("%s: WiFi write map afterf compare success\n", __FUNCTION__);
				sprintf(extra, "WiFi write map compare OK\n");
				err = 0;
				goto exit;
			} else {
				sprintf(extra, "WiFi write map compare FAIL\n");
				RTW_INFO("%s: WiFi write map compare Fail\n", __FUNCTION__);
				err = 0;
				goto exit;
			}
		}
	} else if (strcmp(tmp[0], "wraw") == 0) {
		if ((tmp[1] == NULL) || (tmp[2] == NULL)) {
			err = -EINVAL;
			goto exit;
		}

		addr = simple_strtoul(tmp[1], &ptmp, 16);
		addr &= 0xFFF;

		cnts = strlen(tmp[2]);
		if (cnts % 2) {
			err = -EINVAL;
			goto exit;
		}
		cnts /= 2;
		if (cnts == 0) {
			err = -EINVAL;
			goto exit;
		}

		RTW_INFO("%s: addr=0x%X\n", __FUNCTION__, addr);
		RTW_INFO("%s: cnts=%d\n", __FUNCTION__, cnts);
		RTW_INFO("%s: raw data=%s\n", __FUNCTION__, tmp[2]);

		for (jj = 0, kk = 0; jj < cnts; jj++, kk += 2)
			setrawdata[jj] = key_2char2num(tmp[2][kk], tmp[2][kk + 1]);

		if (rtw_efuse_access(padapter, _TRUE, addr, cnts, setrawdata) == _FAIL) {
			RTW_INFO("%s: rtw_efuse_access error!!\n", __FUNCTION__);
			err = -EFAULT;
			goto exit;
		}
	} 
	
exit:
	if (setdata)
		rtw_mfree(setdata, 1024);
	if (ShadowMapBT)
		rtw_mfree(ShadowMapBT, EFUSE_BT_MAX_MAP_LEN);
	if (ShadowMapWiFi)
		rtw_mfree(ShadowMapWiFi, wifimaplen);
	if (setrawdata)
		rtw_mfree(setrawdata, EFUSE_MAX_SIZE);

	wrqu->length = strlen(extra);

	if (padapter->registrypriv.mp_mode == 0) {
#ifdef CONFIG_IPS
		rtw_pm_set_ips(padapter, ips_mode);
#endif /* CONFIG_IPS */

#ifdef CONFIG_LPS
		rtw_pm_set_lps(padapter, lps_mode);
#endif /* CONFIG_LPS */
	}

	return err;
#endif
}

static int rtw_mp_set(struct net_device *dev, struct rtw_wc_param *iwcp)
{
#if defined(CONFIG_MP_INCLUDED)
	u32 subcmd = iwcp->param1;
	struct net_device *netdev = rtw_get_netdev(dev);
	_adapter *padapter = (_adapter *)rtw_netdev_priv(netdev);
	struct iw_request_info info = {0};
	struct iw_point wrqu = {0};
	char *extra = (char *)iwcp->wc_apps_data;

	RTW_INFO("rtw_mp_set: subcmd = %d \n",subcmd);
		
	if (padapter == NULL)
	{
		return -ENETDOWN;
	}

	if((padapter->bup == _FALSE ))
	{
		RTW_INFO(" %s fail =>(padapter->bup == _FALSE )\n",__FUNCTION__);
		return -ENETDOWN;
	}

	if (RTW_CANNOT_RUN(padapter)) {
		RTW_INFO("%s fail =>(bSurpriseRemoved == _TRUE) || ( bDriverStopped == _TRUE)\n", __func__);
		return -ENETDOWN;
	}

	switch(subcmd)
	{
	case MP_START:
			RTW_INFO("set case mp_start \n");
			rtw_mp_start(dev,&info,&wrqu,extra);
			 break; 
			 
	case MP_STOP:
			RTW_INFO("set case mp_stop \n");
			rtw_mp_stop(dev,&info,&wrqu,extra);
			break; 
			 
	case MP_BANDWIDTH:
			RTW_INFO("set case mp_bandwidth \n");
			rtw_mp_bandwidth(dev,&info,&wrqu,extra);
			break;
				
	case MP_RESET_STATS:
			RTW_INFO("set case MP_RESET_STATS \n");
			rtw_mp_reset_stats(dev,&info,&wrqu,extra);
			break;
			
	case MP_SetRFPathSwh:		
			RTW_INFO("set MP_SetRFPathSwitch \n");
			//rtw_mp_SetRFPath	(dev,info,wdata,extra);
			break;
	case CTA_TEST:
			RTW_INFO("set CTA_TEST\n");
			//rtw_cta_test_start (dev, info, wdata, extra);
			break;
	case MP_DISABLE_BT_COEXIST:
			RTW_INFO("set case MP_DISABLE_BT_COEXIST \n");
			//rtw_mp_disable_bt_coexist(dev, info, wdata, extra);
		break;
#ifdef CONFIG_WOWLAN
	case MP_WOW_ENABLE:
			RTW_INFO("set case MP_WOW_ENABLE: %s\n", extra);
			
			//rtw_wowlan_ctrl(dev, info, wdata, extra);
	break;
	case MP_WOW_SET_PATTERN:
			RTW_INFO("set case MP_WOW_SET_PATTERN: %s\n", extra);
			//rtw_wowlan_set_pattern(dev, info, wdata, extra);
	break;
#endif
#ifdef CONFIG_AP_WOWLAN
	case MP_AP_WOW_ENABLE:
			RTW_INFO("set case MP_AP_WOW_ENABLE: %s\n", extra);
			//rtw_ap_wowlan_ctrl(dev, info, wdata, extra);
	break;
#endif
	}
#endif
	  
	return 0;		
}


static int rtw_mp_get(struct net_device *dev, struct rtw_wc_param *iwcp)
{
#if defined(CONFIG_MP_INCLUDED)
	u32 subcmd = iwcp->param1;
	struct net_device *netdev = rtw_get_netdev(dev);
	_adapter *padapter = (_adapter *)rtw_netdev_priv(netdev);
	struct iw_request_info info = {0};
	struct iw_point wrqu = {0};
//	char extra[512] = {0};

	char* extra = (char *)rtw_zmalloc(2048);
	if(NULL == extra){
		RTW_INFO("can not alloc 2048 byte for extra back info\n");
		return 0;
	}

	wrqu.pointer = (char *)iwcp->wc_apps_data;
	wrqu.length = iwcp->param2;

	if (padapter == NULL)
	{
		return -ENETDOWN;
	}
	if((padapter->bup == _FALSE ))
	{
		RTW_INFO(" %s fail =>(padapter->bup == _FALSE )\n",__FUNCTION__);
		return -ENETDOWN;
	}

	if (RTW_CANNOT_RUN(padapter)) {
		RTW_INFO("%s fail =>(padapter->bSurpriseRemoved == _TRUE) || ( padapter->bDriverStopped == _TRUE)\n", __func__);
		return -ENETDOWN;
	   }
	
	
	switch (subcmd) {
	case WRITE_REG:
			 //rtw_mp_write_reg(dev, &info, &wrqu, extra);
			 break;
			 
	case WRITE_RF:
			//rtw_mp_write_rf(dev, &info, &wrqu, extra);
			 break; 

	case MP_PHYPARA:
			RTW_INFO("set case MP_PHYPARA\n");
			rtw_mp_phypara(dev, &info, &wrqu, extra);
			break;

	case MP_CHANNEL:
			RTW_INFO("set case mp_channel\n");
			rtw_mp_channel(dev , &info, &wrqu, extra);
			break;
			
	case READ_REG:
			RTW_INFO("mp_get  READ_REG\n");
			//rtw_mp_read_reg(dev, info, wrqu, extra);
			 break; 
	case READ_RF:
			RTW_INFO("mp_get  READ_RF\n");
			//rtw_mp_read_rf(dev, info, wrqu, extra);
			break; 
			
	case MP_RATE:
			RTW_INFO("set case mp_rate\n");
			rtw_mp_rate(dev, &info, &wrqu, extra);
			break;
			
	case MP_TXPOWER:
			RTW_INFO("set case MP_TXPOWER\n");
			rtw_mp_txpower(dev, &info, &wrqu, extra);
			break;
			
	case MP_ANT_TX:
			RTW_INFO("set case MP_ANT_TX\n");
			rtw_mp_ant_tx(dev, &info, &wrqu, extra);
			break;
			
	case MP_ANT_RX:
			RTW_INFO("set case MP_ANT_RX\n");
			//rtw_mp_ant_rx(dev, info, wrqu, extra);
			break;
			
	case MP_QUERY:
			rtw_mp_trx_query(dev, &info, &wrqu, extra);
			break;
					
	case MP_CTX:
			RTW_INFO("set case MP_CTX\n");
			rtw_mp_ctx(dev, &info, &wrqu, extra);
			break;
					
	case MP_ARX:
			RTW_INFO("set case MP_ARX\n");
			rtw_mp_arx(dev, &info, &wrqu, extra);
			break;
			
//	case EFUSE_GET:
//			RTW_INFO("efuse get EFUSE_GET\n");
			//rtw_mp_efuse_get(dev, info, wdata, extra);
//		 break; 
		 
	case MP_DUMP:
			RTW_INFO("set case MP_DUMP\n");
			//rtw_mp_dump(dev, info, wrqu, extra);
		 break; 
	case MP_PSD:
			RTW_INFO("set case MP_PSD\n");
			rtw_mp_psd(dev, &info, &wrqu, extra);
		 break;
	case MP_THER:
			RTW_INFO("set case MP_THER\n");
			rtw_mp_thermal(dev, &info, &wrqu, extra);
		break;
	case MP_PwrCtlDM:
			RTW_INFO("set MP_PwrCtlDM\n");
			//rtw_mp_PwrCtlDM(dev, info, wrqu, extra);
		break;
	case MP_QueryDrvStats:		
			RTW_INFO("mp_get MP_QueryDrvStats\n");
			//rtw_mp_QueryDrv(dev, info, wdata, extra);
			break;
	case MP_PWRTRK:
			RTW_INFO("set case MP_PWRTRK\n");
			//rtw_mp_pwrtrk(dev, info, wrqu, extra);
			break;			 
//	case EFUSE_SET:
//			RTW_INFO("set case efuse set\n");
			//rtw_mp_efuse_set(dev, info, wdata, extra);
//			break;			 
	case MP_GET_TXPOWER_INX:
			RTW_INFO("mp_get MP_GET_TXPOWER_INX\n");
			//rtw_mp_txpower_index(dev, info, wrqu, extra);
			break;
	case MP_GETVER:
			RTW_INFO("mp_get MP_GETVER\n");
			//rtw_mp_getver(dev, info, wdata, extra);
			break;
	case MP_MON:
			RTW_INFO("mp_get MP_MON\n");
			//rtw_mp_mon(dev, info, wdata, extra);
			break;
	case EFUSE_MASK:
			RTW_INFO("mp_get EFUSE_MASK\n");
			//rtw_efuse_mask_file(dev, info, wdata, extra);
			break;
	case  EFUSE_FILE:
			RTW_INFO("mp_get EFUSE_FILE\n");
			//rtw_efuse_file_map(dev, info, wdata, extra);
			break;
	case  MP_TX:
			RTW_INFO("mp_get MP_TX\n");
			//rtw_mp_tx(dev, info, wdata, extra);
			break;
	case  MP_RX:
			RTW_INFO("mp_get MP_RX\n");
			//rtw_mp_rx(dev, info, wdata, extra);
			break;

	case EFUSE_GET:
		RTW_INFO("efuse get EFUSE_GET\n");
		rtw_mp_efuse_get(dev, &info, &wrqu, extra);	
		break;
	case EFUSE_SET:
		RTW_INFO("set case efuse set\n");
		rtw_mp_efuse_set(dev, &info, &wrqu, extra);
		break;
#if defined(CONFIG_RTL8723B)
	case MP_SetBT:		
			RTW_INFO("set MP_SetBT\n");
			//rtw_mp_SetBT(dev, info, wdata, extra);
			break;		 
#endif
#ifdef CONFIG_SDIO_INDIRECT_ACCESS
	case MP_SD_IREAD:
		//rtw_mp_sd_iread(dev, info, wrqu, extra);
		break;
	case MP_SD_IWRITE:
		//rtw_mp_sd_iwrite(dev, info, wrqu, extra);
		break;
#endif
	}

	RTW_INFO("%s ",extra);
	
	rtw_msleep_os(10); //delay 10ms for sending pkt before exit adb shell operation
	rtw_mfree(extra,2048);
#endif

return 0;	
}


static int rtw_wpa_supplicant_ioctl(struct net_device *dev, struct rtw_wc_param *iwcp) //wc api
{
	RTW_INFO("Enter rtw_wpa_supplicant_ioctl \n");
}

static int rtw_wx_get_wireless_stats(struct net_device *dev, struct rtw_wc_param *iwcp)
{
	RTW_INFO("Enter rtw_wx_get_wireless_stats \n");
}

static int rtw_wx_set_priv(struct net_device *dev, struct rtw_wc_param *iwcp)
{
	RTW_INFO("Enter rtw_wx_set_priv \n");
}

static int rtw_wx_set_region_code(struct net_device *dev, struct rtw_wc_param *iwcp)
{
	int ret=0;
	struct net_device *netdev = rtw_get_netdev(dev);
	_adapter *padapter = (_adapter *)rtw_netdev_priv(netdev);

	char * country_code = (char*)iwcp->wc_apps_data;
	int len=iwcp->param1;

	if(len > 2)
		return -1;
	
	rtw_set_country_cmd(padapter, RTW_CMDF_WAIT_ACK, country_code, 1);

	return ret;
}


#ifdef CONFIG_AP_MODE
static u8 set_pairwise_key(_adapter *padapter, struct sta_info *psta)
{
	return rtw_ap_set_sta_key(padapter
		, psta->cmn.mac_addr
		, psta->dot118021XPrivacy
		, psta->dot118021x_UncstKey.skey
		, 0
		, 0
	);
}

static int set_wep_key(_adapter *padapter, u8 *key, u8 keylen, int keyid)
{	
	u8 alg;

	switch(keylen)
	{
		case 5:
			alg =_WEP40_;			
			break;
		case 13:
			alg =_WEP104_;			
			break;
		default:
			alg =_NO_PRIVACY_;			
	}

	return rtw_ap_set_group_key(padapter, key, alg, keyid);

}


static int rtw_set_encryption(struct net_device *dev, struct ieee_param *param, u32 param_len)
{
	int ret = 0;
	u32 wep_key_idx, wep_key_len,wep_total_len;
	NDIS_802_11_WEP  *pwep = NULL;
	struct sta_info *psta = NULL, *pbcmc_sta = NULL;	
	struct net_device *netdev = rtw_get_netdev(dev);
	_adapter *padapter = (_adapter *)rtw_netdev_priv(netdev);
	struct mlme_priv	*pmlmepriv = &padapter->mlmepriv;
	struct security_priv* psecuritypriv=&(padapter->securitypriv);
	struct sta_priv *pstapriv = &padapter->stapriv;

	RTW_INFO("%s\n", __FUNCTION__);

	param->u.crypt.err = 0;
	param->u.crypt.alg[IEEE_CRYPT_ALG_NAME_LEN - 1] = '\0';

	//sizeof(struct ieee_param) = 64 bytes;
	//if (param_len !=	(u32) ((u8 *) param->u.crypt.key - (u8 *) param) + param->u.crypt.key_len)
	if (param_len !=  sizeof(struct ieee_param) + param->u.crypt.key_len)
	{
		ret =  -EINVAL;
		goto exit;
	}
	
	if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff &&
			param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff &&
			param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) 
	{
		if (param->u.crypt.idx >= WEP_KEYS)
		{

			ret = -EINVAL;
			goto exit;
		}	
	}
	else 
	{		
		psta = rtw_get_stainfo(pstapriv, param->sta_addr);
		if(!psta)
		{
			//ret = -EINVAL;
			RTW_INFO("rtw_set_encryption(), sta has already been removed or never been added\n");
			goto exit;
		}			
	}

	if (strcmp((const char *)param->u.crypt.alg, "none") == 0 && (psta==NULL))
	{
		//todo:clear default encryption keys
		RTW_INFO("clear default encryption keys, keyid=%d\n", param->u.crypt.idx);

		goto exit;
	}


	if (strcmp((const char *)param->u.crypt.alg, "WEP") == 0 && (psta==NULL))
	{		
		RTW_INFO("r871x_set_encryption, crypt.alg = WEP\n");

		wep_key_idx = param->u.crypt.idx;
		wep_key_len = param->u.crypt.key_len;

		RTW_INFO("r871x_set_encryption, wep_key_idx=%d, len=%d\n", wep_key_idx, wep_key_len);

		if((wep_key_idx >= WEP_KEYS) || (wep_key_len<=0))
		{
			ret = -EINVAL;
			goto exit;
		}


		if (wep_key_len > 0) 
		{			
			wep_key_len = wep_key_len <= 5 ? 5 : 13;
			wep_total_len = wep_key_len + FIELD_OFFSET(NDIS_802_11_WEP, KeyMaterial);
			pwep =(NDIS_802_11_WEP *)rtw_malloc(wep_total_len);
			if(pwep == NULL){
				RTW_INFO(" r871x_set_encryption: pwep allocate fail !!!\n");
				goto exit;
			}

			_rtw_memset(pwep, 0, wep_total_len);

			pwep->KeyLength = wep_key_len;
			pwep->Length = wep_total_len;

		}

		pwep->KeyIndex = wep_key_idx;

		_rtw_memcpy(pwep->KeyMaterial,	param->u.crypt.key, pwep->KeyLength);

		if(param->u.crypt.set_tx)
		{
			RTW_INFO("wep, set_tx=1\n");

			psecuritypriv->ndisencryptstatus = Ndis802_11Encryption1Enabled;
			psecuritypriv->dot11PrivacyAlgrthm=_WEP40_;
			psecuritypriv->dot118021XGrpPrivacy=_WEP40_;

			if(pwep->KeyLength==13)
			{
				psecuritypriv->dot11PrivacyAlgrthm=_WEP104_;
				psecuritypriv->dot118021XGrpPrivacy=_WEP104_;
			}


			psecuritypriv->dot11PrivacyKeyIndex = wep_key_idx;

			_rtw_memcpy(&(psecuritypriv->dot11DefKey[wep_key_idx].skey[0]), pwep->KeyMaterial, pwep->KeyLength);

			psecuritypriv->dot11DefKeylen[wep_key_idx]=pwep->KeyLength;

			set_wep_key(padapter, pwep->KeyMaterial, pwep->KeyLength, wep_key_idx); 	


		}
		else
		{
			RTW_INFO("wep, set_tx=0\n");

			//don't update "psecuritypriv->dot11PrivacyAlgrthm" and 
			//"psecuritypriv->dot11PrivacyKeyIndex=keyid", but can rtw_set_key to cam

			_rtw_memcpy(&(psecuritypriv->dot11DefKey[wep_key_idx].skey[0]), pwep->KeyMaterial, pwep->KeyLength);

			psecuritypriv->dot11DefKeylen[wep_key_idx] = pwep->KeyLength;			

			set_wep_key(padapter, pwep->KeyMaterial, pwep->KeyLength, wep_key_idx);

		}

		goto exit;

	}


	if(!psta && check_fwstate(pmlmepriv, WIFI_AP_STATE)) // //group key
	{
		if(param->u.crypt.set_tx ==1)
		{
			if(strcmp((const char *)param->u.crypt.alg, "WEP") == 0)
			{
				RTW_INFO("%s, set group_key, WEP\n", __FUNCTION__);

				_rtw_memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey,  param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len));

				psecuritypriv->dot118021XGrpPrivacy = _WEP40_;
				if(param->u.crypt.key_len==13)
				{						
					psecuritypriv->dot118021XGrpPrivacy = _WEP104_;
				}

			}
			else if(strcmp((const char *)param->u.crypt.alg, "TKIP") == 0)
			{						
				RTW_INFO("%s, set group_key, TKIP\n", __FUNCTION__);

				psecuritypriv->dot118021XGrpPrivacy = _TKIP_;

				_rtw_memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey,  param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len));

				//DEBUG_ERR("set key length :param->u.crypt.key_len=%d\n", param->u.crypt.key_len);
				//set mic key
				_rtw_memcpy(psecuritypriv->dot118021XGrptxmickey[param->u.crypt.idx].skey, &(param->u.crypt.key[16]), 8);
				_rtw_memcpy(psecuritypriv->dot118021XGrprxmickey[param->u.crypt.idx].skey, &(param->u.crypt.key[24]), 8);

				psecuritypriv->busetkipkey = _TRUE;

			}
			else if(strcmp((const char *)param->u.crypt.alg, "CCMP") == 0)
			{
				RTW_INFO("%s, set group_key, CCMP\n", __FUNCTION__);

				psecuritypriv->dot118021XGrpPrivacy = _AES_;

				_rtw_memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey,  param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len));
			}
			else
			{
				RTW_INFO("%s, set group_key, none\n", __FUNCTION__);

				psecuritypriv->dot118021XGrpPrivacy = _NO_PRIVACY_;
			}

			psecuritypriv->dot118021XGrpKeyid = param->u.crypt.idx;

			psecuritypriv->binstallGrpkey = _TRUE;

			psecuritypriv->dot11PrivacyAlgrthm = psecuritypriv->dot118021XGrpPrivacy;//!!!

			rtw_ap_set_group_key(padapter, param->u.crypt.key, psecuritypriv->dot118021XGrpPrivacy, param->u.crypt.idx);

			pbcmc_sta=rtw_get_bcmc_stainfo(padapter);
			if(pbcmc_sta)
			{
				pbcmc_sta->ieee8021x_blocked = _FALSE;
				pbcmc_sta->dot118021XPrivacy= psecuritypriv->dot118021XGrpPrivacy;//rx will use bmc_sta's dot118021XPrivacy 		
			}	

		}

		goto exit;

	}	

	if(psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_8021X && psta) // psk/802_1x
	{
		if(check_fwstate(pmlmepriv, WIFI_AP_STATE))
		{
			if(param->u.crypt.set_tx ==1)
			{ 
				_rtw_memcpy(psta->dot118021x_UncstKey.skey,  param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len));

				if(strcmp((const char *)param->u.crypt.alg, "WEP") == 0)
				{
					RTW_INFO("%s, set pairwise key, WEP\n", __FUNCTION__);

					psta->dot118021XPrivacy = _WEP40_;
					if(param->u.crypt.key_len==13)
					{						
						psta->dot118021XPrivacy = _WEP104_;
					}
				}
				else if(strcmp((const char *)param->u.crypt.alg, "TKIP") == 0)
				{						
					RTW_INFO("%s, set pairwise key, TKIP\n", __FUNCTION__);

					psta->dot118021XPrivacy = _TKIP_;

					//DEBUG_ERR("set key length :param->u.crypt.key_len=%d\n", param->u.crypt.key_len);
					//set mic key
					_rtw_memcpy(psta->dot11tkiptxmickey.skey, &(param->u.crypt.key[16]), 8);
					_rtw_memcpy(psta->dot11tkiprxmickey.skey, &(param->u.crypt.key[24]), 8);

					psecuritypriv->busetkipkey = _TRUE;

				}
				else if(strcmp((const char *)param->u.crypt.alg, "CCMP") == 0)
				{

					RTW_INFO("%s, set pairwise key, CCMP\n", __FUNCTION__);

					psta->dot118021XPrivacy = _AES_;
				}
				else
				{
					RTW_INFO("%s, set pairwise key, none\n", __FUNCTION__);

					psta->dot118021XPrivacy = _NO_PRIVACY_;
				}

				set_pairwise_key(padapter, psta);

				psta->ieee8021x_blocked = _FALSE;

			}			
			else//group key???
			{ 
				if(strcmp((const char *)param->u.crypt.alg, "WEP") == 0)
				{
					_rtw_memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey,  param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len));

					psecuritypriv->dot118021XGrpPrivacy = _WEP40_;
					if(param->u.crypt.key_len==13)
					{						
						psecuritypriv->dot118021XGrpPrivacy = _WEP104_;
					}
				}
				else if(strcmp((const char *)param->u.crypt.alg, "TKIP") == 0)
				{						
					psecuritypriv->dot118021XGrpPrivacy = _TKIP_;

					_rtw_memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey,  param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len));

					//DEBUG_ERR("set key length :param->u.crypt.key_len=%d\n", param->u.crypt.key_len);
					//set mic key
					_rtw_memcpy(psecuritypriv->dot118021XGrptxmickey[param->u.crypt.idx].skey, &(param->u.crypt.key[16]), 8);
					_rtw_memcpy(psecuritypriv->dot118021XGrprxmickey[param->u.crypt.idx].skey, &(param->u.crypt.key[24]), 8);

					psecuritypriv->busetkipkey = _TRUE;

				}
				else if(strcmp((const char *)param->u.crypt.alg, "CCMP") == 0)
				{
					psecuritypriv->dot118021XGrpPrivacy = _AES_;

					_rtw_memcpy(psecuritypriv->dot118021XGrpKey[param->u.crypt.idx].skey,  param->u.crypt.key, (param->u.crypt.key_len>16 ?16:param->u.crypt.key_len));
				}
				else
				{
					psecuritypriv->dot118021XGrpPrivacy = _NO_PRIVACY_;
				}

				psecuritypriv->dot118021XGrpKeyid = param->u.crypt.idx;

				psecuritypriv->binstallGrpkey = _TRUE;	

				psecuritypriv->dot11PrivacyAlgrthm = psecuritypriv->dot118021XGrpPrivacy;//!!!

				rtw_ap_set_group_key(padapter, param->u.crypt.key, psecuritypriv->dot118021XGrpPrivacy, param->u.crypt.idx);

				pbcmc_sta=rtw_get_bcmc_stainfo(padapter);
				if(pbcmc_sta)
				{
					pbcmc_sta->ieee8021x_blocked = _FALSE;
					pbcmc_sta->dot118021XPrivacy= psecuritypriv->dot118021XGrpPrivacy;//rx will use bmc_sta's dot118021XPrivacy 		
				}					

			}

		}

	}

exit:
	if(pwep)
	{
		rtw_mfree((u8 *)pwep, wep_total_len);		
	}	

	return ret;
}


static int rtw_wx_set_ap(struct net_device *dev, struct rtw_wc_param *iwcp)
{
	int ret = 0;
	struct net_device *netdev = rtw_get_netdev(dev);
	_adapter *padapter = (_adapter *)rtw_netdev_priv(netdev);
	unsigned char *pbuf = iwcp->wc_apps_data;
	unsigned int len = iwcp->param1;
	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
	struct sta_priv *pstapriv = &padapter->stapriv;

	RTW_INFO("%s, len=%d\n", __FUNCTION__, len);

	if(check_fwstate(pmlmepriv, WIFI_AP_STATE) != _TRUE)
		return -EINVAL;

	if(rtw_check_beacon_data(padapter, pbuf,  len) == _SUCCESS)// 12 = param header, 2:no packed
		ret = 0;
	else
		ret = -EINVAL;

	return ret;
}


static int rtw_wx_set_ap_beaocn(struct net_device *dev, struct rtw_wc_param *iwcp)
{
	int ret = 0;
	struct net_device *netdev = rtw_get_netdev(dev);
	_adapter *padapter = (_adapter *)rtw_netdev_priv(netdev);
	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
	WLAN_BSSID_EX *pbss_network = (WLAN_BSSID_EX *)&pmlmepriv->cur_network.network;
	struct security_priv *psecuritypriv = &padapter->securitypriv;
	struct registry_priv *pregistrypriv = &padapter->registrypriv;
	int group_cipher, pairwise_cipher;
	u32 akm;
	u8 mfp_opt = MFP_NO;
	u8 *p;
	u8 *ie = pbss_network->IEs;
	uint ie_len = 0;
	u16 cap, ht_cap = _FALSE;
	u8 OUI1[] = {0x00, 0x50, 0xf2, 0x01};
	u8 WMM_PARA_IE[] = {0x00, 0x50, 0xf2, 0x02, 0x01, 0x01};
	struct rtk_BeaconConf *beaconf = (struct rtk_BeaconConf *)iwcp->wc_apps_data;
	struct rtk_BeaconConf beaconf_tmp;
	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
	u8 *pHT_caps_ie = NULL;
	u8 *pHT_info_ie = NULL;
	u8 vht_cap = _FALSE;
	u8	channel, network_type;
	u8 rf_num = 0;
	int ret_rm;
	struct rf_ctl_t *rfctl = adapter_to_rfctl(padapter);
	HT_CAP_AMPDU_DENSITY best_ampdu_density;
	int len;

	if(check_fwstate(pmlmepriv, WIFI_AP_STATE) != _TRUE)
		return -EINVAL;

    u16 beacon_head_len = (u16)beaconf->headIEsLength;
    u16 beacon_tail_len = (u16)beaconf->tailIEsLength;
    u32 beacon_len = (u32)beacon_head_len + (u32)beacon_tail_len;
    u8 *puc_beacon_info_tmp = (u8 *)(rtw_malloc(beacon_len));

	/* IEs（11b mode，beacon_tail_len = 0） */
	if (beacon_tail_len != 0) {
		_rtw_memcpy(puc_beacon_info_tmp, beaconf->headIEs, beacon_head_len);
		_rtw_memcpy(puc_beacon_info_tmp + beacon_head_len, beaconf->tailIEs, beacon_tail_len);
	} else {
		_rtw_memcpy(puc_beacon_info_tmp, beaconf->headIEs, beacon_head_len);
	}

	beaconf_tmp.headIEs	 = puc_beacon_info_tmp;
    beaconf_tmp.headIEsLength = (u32)beacon_head_len;
    beaconf_tmp.tailIEs 	= puc_beacon_info_tmp + (u32)beacon_head_len;
    beaconf_tmp.tailIEsLength = (u32)beacon_tail_len;

	len = beacon_len - 24;

	RTW_INFO("%s,len=%d\n",__func__, len);

	if (len > MAX_IE_SZ)
		return -1;
	
	pbss_network->IELength = len;

	_rtw_memset(ie, 0, MAX_IE_SZ);

	_rtw_memcpy(ie, puc_beacon_info_tmp+24, pbss_network->IELength);


	if (pbss_network->InfrastructureMode != Ndis802_11APMode
		&& pbss_network->InfrastructureMode != Ndis802_11_mesh
	) {
		rtw_warn_on(1);
		return _FAIL;
	}

	//rtw_ap_check_scan(padapter);


	pbss_network->Rssi = 0;

	_rtw_memcpy(pbss_network->MacAddress, adapter_mac_addr(padapter), ETH_ALEN);

	/* channel */
	channel = pbss_network->Configuration.DSConfig;
	
	/* beacon interval */
	pbss_network->Configuration.BeaconPeriod = beaconf->interval;	
	
	/*	support rate ie & ext support ie & IElen & SupportedRates	*/
	network_type = rtw_update_rate_bymode(pbss_network, pregistrypriv->wireless_mode);

	/* parsing ERP_IE */
	p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _ERPINFO_IE_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_));
	if (p && ie_len > 0)  {
		if(padapter->registrypriv.wireless_mode == WIRELESS_11B ) {

			pbss_network->IELength = pbss_network->IELength - *(p+1) - 2;
			ret_rm = rtw_ies_remove_ie(ie , &beacon_tail_len, _BEACON_IE_OFFSET_, _ERPINFO_IE_,NULL,0);
			RTW_DBG("%s, remove_ie of ERP_IE=%d\n", __FUNCTION__, ret_rm);
		} else 
			ERP_IE_handler(padapter, (PNDIS_802_11_VARIABLE_IEs)p);

	}

	/* capability */
	cap = RTW_GET_LE16(ie);

	/* update privacy/security */
	if (cap & BIT(4))
		pbss_network->Privacy = 1;
	else
		pbss_network->Privacy = 0;

	psecuritypriv->wpa_psk = 0;

	/* wpa2 */
	akm = 0;
	group_cipher = 0;
	pairwise_cipher = 0;
	psecuritypriv->wpa2_group_cipher = _NO_PRIVACY_;
	psecuritypriv->wpa2_pairwise_cipher = _NO_PRIVACY_;
	
	p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _RSN_IE_2_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_));
	if (p && ie_len > 0) {
		if (rtw_parse_wpa2_ie(p, ie_len + 2, &group_cipher, &pairwise_cipher, &akm, &mfp_opt) == _SUCCESS) {
			psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_8021X;
			psecuritypriv->ndisauthtype = Ndis802_11AuthModeWPA2PSK;
			psecuritypriv->dot8021xalg = 1;/* psk,  todo:802.1x */
			psecuritypriv->wpa_psk |= BIT(1);

			psecuritypriv->wpa2_group_cipher = group_cipher;
			psecuritypriv->wpa2_pairwise_cipher = pairwise_cipher;

#ifdef CONFIG_IOCTL_CFG80211
			/*
			Kernel < v5.1, the auth_type set as NL80211_AUTHTYPE_AUTOMATIC 
			in cfg80211_rtw_start_ap().
			if the AKM SAE in the RSN IE, we have to update the auth_type for SAE
			in rtw_check_beacon_data().
			*/
			if (CHECK_BIT(WLAN_AKM_TYPE_SAE, akm))
				psecuritypriv->auth_type = NL80211_AUTHTYPE_SAE;
#endif
		}
	}
	
	/* wpa */
	ie_len = 0;
	group_cipher = 0;
	pairwise_cipher = 0;
	psecuritypriv->wpa_group_cipher = _NO_PRIVACY_;
	psecuritypriv->wpa_pairwise_cipher = _NO_PRIVACY_;
	for (p = ie + _BEACON_IE_OFFSET_; ; p += (ie_len + 2)) {
		p = rtw_get_ie(p, _SSN_IE_1_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_ - (ie_len + 2)));
		if ((p) && (_rtw_memcmp(p + 2, OUI1, 4))) {
			if (rtw_parse_wpa_ie(p, ie_len + 2, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) {
				psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_8021X;
				psecuritypriv->ndisauthtype = Ndis802_11AuthModeWPAPSK;
				psecuritypriv->dot8021xalg = 1;/* psk,  todo:802.1x */

				psecuritypriv->wpa_psk |= BIT(0);

				psecuritypriv->wpa_group_cipher = group_cipher;
				psecuritypriv->wpa_pairwise_cipher = pairwise_cipher;

			}
			break;
		}

		if ((p == NULL) || (ie_len == 0))
			break;

	}
	if (mfp_opt == MFP_INVALID) {
		RTW_INFO(FUNC_ADPT_FMT" invalid MFP setting\n", FUNC_ADPT_ARG(padapter));
		return _FAIL;
	}
	psecuritypriv->mfp_opt = mfp_opt;

	/* wmm */
	ie_len = 0;
	pmlmepriv->qospriv.qos_option = 0;
#ifdef CONFIG_RTW_MESH
	if (MLME_IS_MESH(padapter))
		pmlmepriv->qospriv.qos_option = 1;
#endif
	if (pregistrypriv->wmm_enable) {
		for (p = ie + _BEACON_IE_OFFSET_; ; p += (ie_len + 2)) {
			p = rtw_get_ie(p, _VENDOR_SPECIFIC_IE_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_ - (ie_len + 2)));
			if ((p) && _rtw_memcmp(p + 2, WMM_PARA_IE, 6)) {
				pmlmepriv->qospriv.qos_option = 1;

				*(p + 8) |= BIT(7); /* QoS Info, support U-APSD */

				/* disable all ACM bits since the WMM admission control is not supported */
				*(p + 10) &= ~BIT(4); /* BE */
				*(p + 14) &= ~BIT(4); /* BK */
				*(p + 18) &= ~BIT(4); /* VI */
				*(p + 22) &= ~BIT(4); /* VO */

				WMM_param_handler(padapter, (PNDIS_802_11_VARIABLE_IEs)p);

				break;
			}

			if ((p == NULL) || (ie_len == 0))
				break;
		}
	}
#ifdef CONFIG_80211N_HT
	if(padapter->registrypriv.ht_enable &&
		is_supported_ht(padapter->registrypriv.wireless_mode)) {
		/* parsing HT_CAP_IE */
		p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _HT_CAPABILITY_IE_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_));
		if (p && ie_len > 0) {
			HT_CAP_AMPDU_FACTOR max_rx_ampdu_factor = MAX_AMPDU_FACTOR_64K;
			struct rtw_ieee80211_ht_cap *pht_cap = (struct rtw_ieee80211_ht_cap *)(p + 2);

			if (0) {
				RTW_INFO(FUNC_ADPT_FMT" HT_CAP_IE from upper layer:\n", FUNC_ADPT_ARG(padapter));
				dump_ht_cap_ie_content(RTW_DBGDUMP, p + 2, ie_len);
			}

			pHT_caps_ie = p;

			ht_cap = _TRUE;
			network_type |= WIRELESS_11_24N;

			rtw_ht_use_default_setting(padapter);

			/* Update HT Capabilities Info field */
			if (pmlmepriv->htpriv.sgi_20m == _FALSE)
				pht_cap->cap_info &= ~(IEEE80211_HT_CAP_SGI_20);

			if (pmlmepriv->htpriv.sgi_40m == _FALSE)
				pht_cap->cap_info &= ~(IEEE80211_HT_CAP_SGI_40);

			if (!TEST_FLAG(pmlmepriv->htpriv.ldpc_cap, LDPC_HT_ENABLE_RX))
				pht_cap->cap_info &= ~(IEEE80211_HT_CAP_LDPC_CODING);

			if (!TEST_FLAG(pmlmepriv->htpriv.stbc_cap, STBC_HT_ENABLE_TX))
				pht_cap->cap_info &= ~(IEEE80211_HT_CAP_TX_STBC);

			if (!TEST_FLAG(pmlmepriv->htpriv.stbc_cap, STBC_HT_ENABLE_RX))
				pht_cap->cap_info &= ~(IEEE80211_HT_CAP_RX_STBC_3R);

			/* Update A-MPDU Parameters field */
			pht_cap->ampdu_params_info &= ~(IEEE80211_HT_CAP_AMPDU_FACTOR | IEEE80211_HT_CAP_AMPDU_DENSITY);

			if ((psecuritypriv->wpa_pairwise_cipher & WPA_CIPHER_CCMP) ||
				(psecuritypriv->wpa2_pairwise_cipher & WPA_CIPHER_CCMP)) {
				rtw_hal_get_def_var(padapter, HW_VAR_BEST_AMPDU_DENSITY, &best_ampdu_density);
				pht_cap->ampdu_params_info |= (IEEE80211_HT_CAP_AMPDU_DENSITY & (best_ampdu_density << 2));
			} else
				pht_cap->ampdu_params_info |= (IEEE80211_HT_CAP_AMPDU_DENSITY & 0x00);

			rtw_hal_get_def_var(padapter, HW_VAR_MAX_RX_AMPDU_FACTOR, &max_rx_ampdu_factor);
			pht_cap->ampdu_params_info |= (IEEE80211_HT_CAP_AMPDU_FACTOR & max_rx_ampdu_factor); /* set  Max Rx AMPDU size	to 64K */

			_rtw_memcpy(&(pmlmeinfo->HT_caps), pht_cap, sizeof(struct HT_caps_element));

			/* Update Supported MCS Set field */
			{
				u8 rx_nss = 0;
				int i;

				rx_nss = GET_HAL_RX_NSS(padapter);

				/* RX MCS Bitmask */
				switch (rx_nss) {
				case 1:
					set_mcs_rate_by_mask(HT_CAP_ELE_RX_MCS_MAP(pht_cap), MCS_RATE_1R);
					break;
				case 2:
					set_mcs_rate_by_mask(HT_CAP_ELE_RX_MCS_MAP(pht_cap), MCS_RATE_2R);
					break;
				case 3:
					set_mcs_rate_by_mask(HT_CAP_ELE_RX_MCS_MAP(pht_cap), MCS_RATE_3R);
					break;
				case 4:
					set_mcs_rate_by_mask(HT_CAP_ELE_RX_MCS_MAP(pht_cap), MCS_RATE_4R);
					break;
				default:
					RTW_WARN("rf_type:%d or rx_nss:%u is not expected\n", GET_HAL_RFPATH(padapter), rx_nss);
				}
				for (i = 0; i < 10; i++)
					*(HT_CAP_ELE_RX_MCS_MAP(pht_cap) + i) &= padapter->mlmeextpriv.default_supported_mcs_set[i];
			}

#ifdef CONFIG_BEAMFORMING
			/* Use registry value to enable HT Beamforming. */
			/* ToDo: use configure file to set these capability. */
			pht_cap->tx_BF_cap_info = 0;

			/* HT Beamformer */
			if (TEST_FLAG(pmlmepriv->htpriv.beamform_cap, BEAMFORMING_HT_BEAMFORMER_ENABLE)) {
				/* Transmit NDP Capable */
				SET_HT_CAP_TXBF_TRANSMIT_NDP_CAP(pht_cap, 1);
				/* Explicit Compressed Steering Capable */
				SET_HT_CAP_TXBF_EXPLICIT_COMP_STEERING_CAP(pht_cap, 1);
				/* Compressed Steering Number Antennas */
				SET_HT_CAP_TXBF_COMP_STEERING_NUM_ANTENNAS(pht_cap, 1);
				rtw_hal_get_def_var(padapter, HAL_DEF_BEAMFORMER_CAP, (u8 *)&rf_num);
				SET_HT_CAP_TXBF_CHNL_ESTIMATION_NUM_ANTENNAS(pht_cap, rf_num);
			}

			/* HT Beamformee */
			if (TEST_FLAG(pmlmepriv->htpriv.beamform_cap, BEAMFORMING_HT_BEAMFORMEE_ENABLE)) {
				/* Receive NDP Capable */
				SET_HT_CAP_TXBF_RECEIVE_NDP_CAP(pht_cap, 1);
				/* Explicit Compressed Beamforming Feedback Capable */
				SET_HT_CAP_TXBF_EXPLICIT_COMP_FEEDBACK_CAP(pht_cap, 2);
				rtw_hal_get_def_var(padapter, HAL_DEF_BEAMFORMEE_CAP, (u8 *)&rf_num);
				SET_HT_CAP_TXBF_COMP_STEERING_NUM_ANTENNAS(pht_cap, rf_num);
			}
#endif /* CONFIG_BEAMFORMING */

			_rtw_memcpy(&pmlmepriv->htpriv.ht_cap, p + 2, ie_len);

			if (0) {
				RTW_INFO(FUNC_ADPT_FMT" HT_CAP_IE driver masked:\n", FUNC_ADPT_ARG(padapter));
				dump_ht_cap_ie_content(RTW_DBGDUMP, p + 2, ie_len);
			}
		}

		/* parsing HT_INFO_IE */
		p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, _HT_ADD_INFO_IE_, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_));
		if (p && ie_len > 0) {
			pHT_info_ie = p;
			if (channel == 0)
				pbss_network->Configuration.DSConfig = GET_HT_OP_ELE_PRI_CHL(pHT_info_ie + 2);
			else if (channel != GET_HT_OP_ELE_PRI_CHL(pHT_info_ie + 2)) {
				RTW_INFO(FUNC_ADPT_FMT" ch inconsistent, DSSS:%u, HT primary:%u\n"
					, FUNC_ADPT_ARG(padapter), channel, GET_HT_OP_ELE_PRI_CHL(pHT_info_ie + 2));
			}
		}
	}
#endif /* CONFIG_80211N_HT */
	pmlmepriv->cur_network.network_type = network_type;

#ifdef CONFIG_80211N_HT
	pmlmepriv->htpriv.ht_option = _FALSE;

	if ((psecuritypriv->wpa2_pairwise_cipher & WPA_CIPHER_TKIP) ||
		(psecuritypriv->wpa_pairwise_cipher & WPA_CIPHER_TKIP)) {
		/* todo: */
		/* ht_cap = _FALSE; */
	}

	/* ht_cap	 */
	if (padapter->registrypriv.ht_enable &&
		is_supported_ht(padapter->registrypriv.wireless_mode) && ht_cap == _TRUE) {

		pmlmepriv->htpriv.ht_option = _TRUE;
		pmlmepriv->qospriv.qos_option = 1;

		pmlmepriv->htpriv.ampdu_enable = pregistrypriv->ampdu_enable ? _TRUE : _FALSE;

		HT_caps_handler(padapter, (PNDIS_802_11_VARIABLE_IEs)pHT_caps_ie);

		HT_info_handler(padapter, (PNDIS_802_11_VARIABLE_IEs)pHT_info_ie);
	}
#endif

#ifdef CONFIG_80211AC_VHT
	pmlmepriv->ori_vht_en = 0;
	pmlmepriv->vhtpriv.vht_option = _FALSE;

	if (pmlmepriv->htpriv.ht_option == _TRUE
		&& pbss_network->Configuration.DSConfig > 14
		&& REGSTY_IS_11AC_ENABLE(pregistrypriv)
		&& is_supported_vht(pregistrypriv->wireless_mode)
		&& (!rfctl->country_ent || COUNTRY_CHPLAN_EN_11AC(rfctl->country_ent))
	) {
		/* Parsing VHT CAP IE */
		p = rtw_get_ie(ie + _BEACON_IE_OFFSET_, EID_VHTCapability, &ie_len, (pbss_network->IELength - _BEACON_IE_OFFSET_));
		if (p && ie_len > 0)
			vht_cap = _TRUE;

		/* Parsing VHT OPERATION IE */

		if (vht_cap == _TRUE
			&& MLME_IS_MESH(padapter) /* allow only mesh temporarily before VHT IE checking is ready */
		) {
			rtw_check_for_vht20(padapter, ie + _BEACON_IE_OFFSET_, pbss_network->IELength - _BEACON_IE_OFFSET_);
			pmlmepriv->ori_vht_en = 1;
			pmlmepriv->vhtpriv.vht_option = _TRUE;
		} else if (REGSTY_IS_11AC_AUTO(pregistrypriv)) {
			rtw_vht_ies_detach(padapter, pbss_network);
			rtw_vht_ies_attach(padapter, pbss_network);
		}
	}

	if (pmlmepriv->vhtpriv.vht_option == _FALSE)
		rtw_vht_ies_detach(padapter, pbss_network);
#endif /* CONFIG_80211AC_VHT */

#ifdef CONFIG_80211N_HT
	if(padapter->registrypriv.ht_enable &&
					is_supported_ht(padapter->registrypriv.wireless_mode) &&
		pbss_network->Configuration.DSConfig <= 14 && padapter->registrypriv.wifi_spec == 1 &&
		pbss_network->IELength + 10 <= MAX_IE_SZ) {
		uint len = 0;

		SET_EXT_CAPABILITY_ELE_BSS_COEXIST(pmlmepriv->ext_capab_ie_data, 1);
		pmlmepriv->ext_capab_ie_len = 10;
		rtw_set_ie(pbss_network->IEs + pbss_network->IELength, EID_EXTCapability, 8, pmlmepriv->ext_capab_ie_data, &len);
		pbss_network->IELength += pmlmepriv->ext_capab_ie_len;
	}
#endif /* CONFIG_80211N_HT */

	pbss_network->Length = get_WLAN_BSSID_EX_sz((WLAN_BSSID_EX *)pbss_network);

	rtw_ies_get_chbw(pbss_network->IEs + _BEACON_IE_OFFSET_, pbss_network->IELength - _BEACON_IE_OFFSET_
		, &pmlmepriv->ori_ch, &pmlmepriv->ori_bw, &pmlmepriv->ori_offset, 1, 1);
	rtw_warn_on(pmlmepriv->ori_ch == 0);

	_rtw_mfree(puc_beacon_info_tmp, beacon_len);

	return ret;
}


static int rtw_wx_set_ap_config(struct net_device *dev, struct rtw_wc_param *iwcp)
{
	int ret = 0;
	struct net_device *netdev = rtw_get_netdev(dev);
	_adapter *padapter = (_adapter *)rtw_netdev_priv(netdev);
	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
	WLAN_BSSID_EX *pbss_network = (WLAN_BSSID_EX *)&pmlmepriv->cur_network.network;
	struct rtk_APConf *apconf=(struct rtk_APConf *)iwcp->wc_apps_data;	
	int channel;
	int width;
	if(check_fwstate(pmlmepriv, WIFI_AP_STATE) != _TRUE)
		return -EINVAL;

	/* SSID */
	_rtw_memset(&pbss_network->Ssid, 0, sizeof(NDIS_802_11_SSID));
	_rtw_memcpy(pbss_network->Ssid.Ssid, apconf->ssid, apconf->ssidLen);
	pbss_network->Ssid.SsidLength = apconf->ssidLen;
#ifdef CONFIG_P2P
	_rtw_memcpy(padapter->wdinfo.p2p_group_ssid, pbss_network->Ssid.Ssid, pbss_network->Ssid.SsidLength);
	padapter->wdinfo.p2p_group_ssid_len = pbss_network->Ssid.SsidLength;
#endif

	/* chnnel */
	channel = 0;
	pbss_network->Configuration.Length = 0;
	channel = apconf->channel;
	pbss_network->Configuration.DSConfig = channel;	

	padapter->mlmeextpriv.cur_channel = channel;
	
	RTW_INFO("%s: set to channel %d\n", __func__, padapter->mlmeextpriv.cur_channel);

	width = apconf->width;

	if(width == 1)
	{
		set_channel_bwmode(padapter, padapter->mlmeextpriv.cur_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, CHANNEL_WIDTH_20);
	}
	else if(width == 2)
	{
		set_channel_bwmode(padapter, padapter->mlmeextpriv.cur_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, CHANNEL_WIDTH_40);
	}
	
	return ret;
}

static int rtw_wx_set_ap_start(struct net_device *dev, struct rtw_wc_param *iwcp)
{
	int ret = 0;
	struct net_device *netdev = rtw_get_netdev(dev);
	_adapter *padapter = (_adapter *)rtw_netdev_priv(netdev);
	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
	WLAN_BSSID_EX *pbss_network = (WLAN_BSSID_EX *)&pmlmepriv->cur_network.network;
	

	{
		/* alloc sta_info for ap itself */

		struct sta_info *sta;

		sta = rtw_get_stainfo(&padapter->stapriv, pbss_network->MacAddress);
		if (!sta) {
			sta = rtw_alloc_stainfo(&padapter->stapriv, pbss_network->MacAddress);
			if (sta == NULL)
				return _FAIL;
		}
	}

	rtw_startbss_cmd(padapter, RTW_CMDF_WAIT_ACK);
	{
		int sk_band = RTW_GET_SCAN_BAND_SKIP(padapter);

		if (sk_band)
			RTW_CLR_SCAN_BAND_SKIP(padapter, sk_band);
	}

	rtw_indicate_connect(padapter);

	pmlmepriv->cur_network.join_res = _TRUE;/* for check if already set beacon */

	/* update bc/mc sta_info */
	/* update_bmc_sta(padapter); */


	return ret;
}

static int rtw_wx_get_sta_num(struct net_device *dev, struct rtw_wc_param *iwcp)
{
	int ret=0;
	struct net_device *netdev = rtw_get_netdev(dev);
	_adapter *padapter = (_adapter *)rtw_netdev_priv(netdev);	
    struct sta_priv *pstapriv = &(padapter->stapriv);
	int ie_len;
    u8 num = 0;
    _irqL irqL;
    _list *phead, *plist;
    struct sta_info *psta = NULL;

	RTW_INFO("%s\n", __FUNCTION__);

	if(check_fwstate(&(padapter->mlmepriv), WIFI_AP_STATE) != _TRUE)
		return -EINVAL;

	_enter_critical_bh(&pstapriv->asoc_list_lock, &irqL);
	
	phead = &pstapriv->asoc_list;
	plist = rtw_get_next(phead);
	
	while ((rtw_end_of_queue_search(phead, plist)) == _FALSE){
		//psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list);
		num++;
		plist = rtw_get_next(plist);	
	}

	_exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
    
    *(u8*)iwcp->wc_apps_data = num;

	return ret;
}

static int rtw_wx_get_client_list(struct net_device *dev, struct rtw_wc_param *iwcp)
{
	struct net_device *netdev = rtw_get_netdev(dev);
	_adapter *padapter = (_adapter *)rtw_netdev_priv(netdev);
	struct sta_priv *pstapriv = &(padapter->stapriv);
	int i = 0;
	_irqL irqL;
	_list	*phead, *plist;
	struct sta_info *psta = NULL;	
	struct rtk_WifiStaInfo * mac_list = (struct rtk_WifiStaInfo*)(iwcp->wc_apps_data);
	u8 num = iwcp->param1;
	if(check_fwstate(&(padapter->mlmepriv), WIFI_AP_STATE) != _TRUE)
		return -1;


	_enter_critical_bh(&pstapriv->asoc_list_lock, &irqL);
	
	phead = &pstapriv->asoc_list;
	plist = rtw_get_next(phead);
	while ((rtw_end_of_queue_search(phead, plist)) == _FALSE)	
	{
		psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list);
		_rtw_memcpy(mac_list+i, psta->cmn.mac_addr, 6);
		i++;
		if(i >= num) break;
		plist = rtw_get_next(plist);
		
	}

	_exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
	
	return 0;
}

static int rtw_wx_get_new_sta_wpa_ie(struct net_device *dev, struct rtw_wc_param *iwcp)
{
	int ret=0;	
	struct net_device *netdev = rtw_get_netdev(dev);
	_adapter *padapter = (_adapter *)rtw_netdev_priv(netdev);
	struct sta_info *psta = NULL;
	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
	struct sta_priv *pstapriv = &padapter->stapriv;
	unsigned char *pbuf = iwcp->wc_apps_data;
	unsigned char sta_addr[6];

	_rtw_memcpy(sta_addr,iwcp->wc_apps_cb,6);

	RTW_INFO("rtw_wx_get_new_sta_wpa_ie, sta_addr: " MAC_FMT "\n", MAC_ARG(sta_addr));

	if(check_fwstate(pmlmepriv, (_FW_LINKED|WIFI_AP_STATE)) != _TRUE)		
	{
		return -EINVAL;		
	}

	if (sta_addr[0] == 0xff && sta_addr[1] == 0xff &&
	   sta_addr[2] == 0xff && sta_addr[3] == 0xff &&
	   sta_addr[4] == 0xff && sta_addr[5] == 0xff) 
	{
		return -EINVAL;	
	}

	psta = rtw_get_stainfo(pstapriv, sta_addr);
	if(psta)
	{
		if((psta->wpa_ie[0] == WLAN_EID_RSN) || (psta->wpa_ie[0] == WLAN_EID_GENERIC))
		{
			int wpa_ie_len;
			int copy_len;

			wpa_ie_len = psta->wpa_ie[1];
			
			copy_len = ((wpa_ie_len+2) > sizeof(psta->wpa_ie)) ? (sizeof(psta->wpa_ie)):(wpa_ie_len+2);
				
			iwcp->param1 = copy_len;

			_rtw_memcpy(pbuf, psta->wpa_ie, copy_len);
		}
		else
		{
			RTW_INFO("sta's wpa_ie is NONE\n");
		}		
	}
	else
	{
		ret = -1;
	}

	return ret;
}

static int rtw_wx_set_sta_flush(struct net_device *dev, struct rtw_wc_param *iwcp)
{
	int ret=0;	
	struct net_device *netdev = rtw_get_netdev(dev);
	_adapter *padapter = (_adapter *)rtw_netdev_priv(netdev);	

	RTW_INFO("%s\n", __FUNCTION__);

	flush_all_cam_entry(padapter);	//clear CAM

	ret = rtw_sta_flush(padapter, _TRUE);	

	return ret;
}

static int rtw_wx_set_sta_remove(struct net_device *dev, struct rtw_wc_param *iwcp)
{
	_irqL irqL;
	int ret=0;	
	struct sta_info *psta = NULL;
	struct net_device *netdev = rtw_get_netdev(dev);
	_adapter *padapter = (_adapter *)rtw_netdev_priv(netdev);
	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
	struct sta_priv *pstapriv = &padapter->stapriv;
	unsigned char sta_addr[6];

	_rtw_memcpy(sta_addr,iwcp->wc_apps_data,6);

	RTW_INFO("rtw_del_sta=" MAC_FMT "\n", MAC_ARG(sta_addr));

		
	if(check_fwstate(pmlmepriv, (_FW_LINKED|WIFI_AP_STATE)) != _TRUE)		
	{
		return -EINVAL;		
	}

	if (sta_addr[0] == 0xff && sta_addr[1] == 0xff &&
	    sta_addr[2] == 0xff && sta_addr[3] == 0xff &&
	    sta_addr[4] == 0xff && sta_addr[5] == 0xff) 
	{
		return -EINVAL;	
	}

	psta = rtw_get_stainfo(pstapriv, iwcp->wc_apps_data);
	if(psta)
	{
		u8 updated = 0;
	
		_enter_critical_bh(&pstapriv->asoc_list_lock, &irqL);
		if(rtw_is_list_empty(&psta->asoc_list)==_FALSE)
		{			
			rtw_list_delete(&psta->asoc_list);
			pstapriv->asoc_list_cnt--;
			updated = rtw_ap_free_sta(padapter, psta, _TRUE, WLAN_REASON_DEAUTH_LEAVING, _TRUE);

		}
		_exit_critical_bh(&pstapriv->asoc_list_lock, &irqL);
		
		associated_clients_update(padapter, updated, STA_INFO_UPDATE_PROTECTION_MODE);
	
		psta = NULL;
		
	}
	else
	{
		RTW_INFO("rtw_del_sta(), sta has already been removed or never been added\n");
	}
	return ret;
}

static int rtw_wx_set_wps_bcn_ie(struct net_device *dev, struct rtw_wc_param *iwcp)
{
	int ret=0;
	unsigned char wps_oui[4]={0x0,0x50,0xf2,0x04};
	struct net_device *netdev = rtw_get_netdev(dev);
	_adapter *padapter = (_adapter *)rtw_netdev_priv(netdev);	
	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
	struct mlme_ext_priv	*pmlmeext = &(padapter->mlmeextpriv);
	struct mlme_ext_info	*pmlmeinfo = &(pmlmeext->mlmext_info);
	int ie_len;


	if(check_fwstate(pmlmepriv, WIFI_AP_STATE) != _TRUE)
		return -EINVAL;

	ie_len = iwcp->param1;

	RTW_INFO("%s, len=%d\n", __FUNCTION__, ie_len);

	if(pmlmepriv->wps_beacon_ie)
	{
		rtw_mfree(pmlmepriv->wps_beacon_ie, pmlmepriv->wps_beacon_ie_len);
		pmlmepriv->wps_beacon_ie = NULL;			
	}	

	if(ie_len>0)
	{
		pmlmepriv->wps_beacon_ie = rtw_malloc(ie_len);
		pmlmepriv->wps_beacon_ie_len = ie_len;
		if ( pmlmepriv->wps_beacon_ie == NULL) {
			RTW_INFO("%s()-%d: rtw_malloc() ERROR!\n", __FUNCTION__, __LINE__);
			return -EINVAL;
		}

		_rtw_memcpy(pmlmepriv->wps_beacon_ie, iwcp->wc_apps_data, ie_len);

        update_beacon(padapter, _VENDOR_SPECIFIC_IE_, wps_oui, _TRUE, 0);
		
		pmlmeext->bstart_bss = _TRUE;
		
	}

	return ret; 	

}

static int rtw_wx_set_wps_probe_resp_ie(struct net_device *dev, struct rtw_wc_param *iwcp)
{
	int ret=0;
	struct net_device *netdev = rtw_get_netdev(dev);
	_adapter *padapter = (_adapter *)rtw_netdev_priv(netdev);	
	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
	int ie_len;

	ie_len = iwcp->param1;

	RTW_INFO("%s, len=%d\n", __FUNCTION__, ie_len);

	if(check_fwstate(pmlmepriv, WIFI_AP_STATE) != _TRUE)
		return -EINVAL;

	if(pmlmepriv->wps_probe_resp_ie)
	{
		rtw_mfree(pmlmepriv->wps_probe_resp_ie, pmlmepriv->wps_probe_resp_ie_len);
		pmlmepriv->wps_probe_resp_ie = NULL;			
	}	

	if(ie_len>0)
	{
		pmlmepriv->wps_probe_resp_ie = rtw_malloc(ie_len);
		pmlmepriv->wps_probe_resp_ie_len = ie_len;
		if ( pmlmepriv->wps_probe_resp_ie == NULL) {
			RTW_INFO("%s()-%d: rtw_malloc() ERROR!\n", __FUNCTION__, __LINE__);
			return -EINVAL;
		}
		_rtw_memcpy(pmlmepriv->wps_probe_resp_ie, iwcp->wc_apps_data, ie_len); 	
	}
	
	
	return ret;

}

static int rtw_wx_set_wps_assoc_resp_ie(struct net_device *dev, struct rtw_wc_param *iwcp)
{
	int ret=0;
	struct net_device *netdev = rtw_get_netdev(dev);
	_adapter *padapter = (_adapter *)rtw_netdev_priv(netdev);	
	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
	int ie_len;


	if(check_fwstate(pmlmepriv, WIFI_AP_STATE) != _TRUE)
		return -EINVAL;

	ie_len = iwcp->param1;// 12 = param header, 2:no packed

	RTW_INFO("%s, len=%d\n", __FUNCTION__, ie_len);

	if(pmlmepriv->wps_assoc_resp_ie)
	{
		rtw_mfree(pmlmepriv->wps_assoc_resp_ie, pmlmepriv->wps_assoc_resp_ie_len);
		pmlmepriv->wps_assoc_resp_ie = NULL;			
	}	

	if(ie_len>0)
	{
		pmlmepriv->wps_assoc_resp_ie = rtw_malloc(ie_len);
		pmlmepriv->wps_assoc_resp_ie_len = ie_len;
		if ( pmlmepriv->wps_assoc_resp_ie == NULL) {
			RTW_INFO("%s()-%d: rtw_malloc() ERROR!\n", __FUNCTION__, __LINE__);
			return -EINVAL;
		}
		
		_rtw_memcpy(pmlmepriv->wps_assoc_resp_ie, iwcp->wc_apps_data, ie_len); 	
	}
		
	return ret;

}

static int rtw_wx_set_encryption(struct net_device *dev, struct rtw_wc_param *iwcp)
{
	int ret=0;
	struct net_device *netdev = rtw_get_netdev(dev);
	_adapter *padapter = (_adapter *)rtw_netdev_priv(netdev);	
	struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
	int ie_len;

	RTW_INFO("%s\n", __FUNCTION__);

	if(check_fwstate(pmlmepriv, WIFI_AP_STATE) != _TRUE)
		return -EINVAL;

	rtw_set_encryption(dev, iwcp->wc_apps_data, iwcp->param1);

	return ret;

}

#endif

const wlan_conf_handler rtw_handlers[] =
{
	(wlan_conf_handler) rtw_wx_set_freq,		/* SIOCSIWFREQ  */ /* WC_SET_FREQ  */
	(wlan_conf_handler) rtw_wx_get_freq,		/* SIOCGIWFREQ  */ /* WC_GET_FREQ  */
	(wlan_conf_handler) rtw_wx_channel_list,    /* WC_GET_CHANNEL_PLAN */
	(wlan_conf_handler) rtw_wx_set_mode,		/* SIOCSIWMODE  */ /* WC_SET_MODE  */
	(wlan_conf_handler) rtw_wx_get_mode,		/* SIOCGIWMODE  */ /* WC_GET_MODE  */ 
	(wlan_conf_handler) rtw_wx_set_auth,		/* SIOCSIWAUTH  */ /* WC_SET_AUTH  */
	(wlan_conf_handler) NULL,                   /* SIOCGIWAUTH  */ /* WC_GET_AUTH  */  
	(wlan_conf_handler) rtw_wx_set_wap,         /* SIOCSIWAP    */ /* WC_SET_BSSID */
	(wlan_conf_handler) rtw_wx_get_wap,         /* SIOGSIWAP    */ /* WC_GET_BSSID */
	(wlan_conf_handler) rtw_wx_set_essid,       /* SIOCSIWESSID */ /* WC_SET_ESSID */
	(wlan_conf_handler) rtw_wx_get_essid,       /* SIOCGIWESSID */ /* WC_GET_ESSID */  
	(wlan_conf_handler) rtw_wx_set_rate,        /* SIOCSIWRATE  */ /* WC_SET_RATE  */
	(wlan_conf_handler) rtw_wx_get_rate,        /* SIOCGIWRATE  */ /* WC_GET_RATE  */
	(wlan_conf_handler) rtw_wx_support_rate,    /* WC_GET_RATE  */
	(wlan_conf_handler) rtw_wx_set_rts,         /* SIOCSIWRTS   */ /* WC_SET_RTS   */
	(wlan_conf_handler) rtw_wx_get_rts,         /* SIOCGIWRTS   */ /* WC_GET_RTS   */
	(wlan_conf_handler) rtw_wx_set_frag,        /* SIOCSIWFRAG  */ /* WC_SET_FRAG  */
	(wlan_conf_handler) rtw_wx_get_frag,        /* SIOCGIWFRAG  */ /* WC_GET_FRAG  */
	(wlan_conf_handler) rtw_wx_set_txpow,       /* SIOCSIWTXPOW */ /* WC_SET_TXPOW */
	(wlan_conf_handler) NULL,                   /* SIOCGIWTXPOW */ /* WC_GET_TXPOW */
	(wlan_conf_handler) NULL,                   /* SIOCSIWPOWER */ /* WC_SET_POWER */
	(wlan_conf_handler) rtw_wx_get_power,       /* SIOCGIWPOWER */ /* WC_GET_POWER */
	(wlan_conf_handler) rtw_wx_set_scan,		/* SIOCSIWSCAN  */ /* WC_SET_SCAN  */
	(wlan_conf_handler) rtw_wx_abort_scan,		/* WC_Abort_SCAN  */
	(wlan_conf_handler) rtw_wx_get_scan,		/* SIOCGIWSCAN  */ /* WC_GET_SCAN  */
	(wlan_conf_handler) NULL,                   /* WC_GET_SCAN_IE */
	(wlan_conf_handler) rtw_wx_site_survey,     /* WC_GET_EXT_SCAN */
	(wlan_conf_handler) rtw_wx_set_enc,         /* WC_SET_WEPMODE  */
	(wlan_conf_handler) rtw_wx_get_enc,         /* WC_GET_WEPMODE  */
	(wlan_conf_handler) NULL,                   /* WC_SET_RETRY    */
	(wlan_conf_handler) rtw_wx_get_retry,       /* WC_GET_RETRY    */
	(wlan_conf_handler) NULL,					/* WC_SET_MAC */
	(wlan_conf_handler) rtw_get_own_mac,		/* WC_GET_MAC */
	(wlan_conf_handler) rtw_wx_write_mac,		/* WC_WRITE_ADDR*/
	(wlan_conf_handler) NULL,					/* WC_SET_DEAUTH */
	(wlan_conf_handler) rtw_wps_start, 		    /* WC_SET_WPS_SESSION */ 
	(wlan_conf_handler) NULL,					/* WC_SET_MULTICAST_MODE */
	(wlan_conf_handler) NULL,					/* WC_SET_GET_BAND */
	(wlan_conf_handler) NULL,					/* WC_SET_CONN_CB */
	(wlan_conf_handler) rtw_wx_set_gen_ie,      /* WC_SET_GEN_IE */
	(wlan_conf_handler) NULL,					/* WC_GET_GEN_IE */
	(wlan_conf_handler) rtw_wx_set_priv,        /* WC_SET_PRIVATE  */
	(wlan_conf_handler) rtw_wx_set_mlme,		/* request MLME operation; uses struct iw_mlme */
	(wlan_conf_handler) rtw_wx_add_key,         /* WC_ADD_KEY */ 
	(wlan_conf_handler) rtw_wx_set_default_key, /* WC_SET_DEFAULT_KEY */         
	(wlan_conf_handler) rtw_wx_del_key,		    /* WC_DEL_KEY */
	(wlan_conf_handler) rtw_wx_set_enc_ext,		/* SIOCSIWENCODEEXT */
	(wlan_conf_handler) NULL,					/* SIOCGIWENCODEEXT */
	(wlan_conf_handler) rtw_wx_set_pmkid,		/* SIOCSIWPMKSA */
	(wlan_conf_handler) rtw_wx_get_wireless_stats,/* WC_GET_STATS */
	(wlan_conf_handler) rtw_wpa_supplicant_ioctl, /*WC_WPA_IOCTL */
	(wlan_conf_handler) NULL,		/* WC_SET_HOSTAPD_IOCTL */	
	(wlan_conf_handler) NULL,			/* WC_SET_P2P */
	(wlan_conf_handler) NULL,			/* WC_GET_P2P */
	(wlan_conf_handler) NULL,			/* WC_GET2_P2P */
	(wlan_conf_handler) rtw_set_pid,			/* WC_SET_PID */
	(wlan_conf_handler) rtw_get_ap_info,		/* WC_GET_AP_INFO */ 
	(wlan_conf_handler) rtw_wx_set_channel_plan, /* WC_SET_CHANNEL_PLAN */
	(wlan_conf_handler) rtw_wx_write32,			/* WC_SET_WRITE32 */
	(wlan_conf_handler) rtw_wx_read32,			/* WC_GET_READ32 */
	(wlan_conf_handler) rtw_wx_write_rf,		/* WC_SET_RF */
	(wlan_conf_handler) rtw_wx_read_rf,			/* WC_GET_RF */
	(wlan_conf_handler) rtw_dbg_port,			/* WC_SET_DBG_PORT */
	(wlan_conf_handler) rtw_mp_set,             /* WC_SET_MP */ 
	(wlan_conf_handler) rtw_mp_get,             /* WC_GET_MP */
	(wlan_conf_handler) rtw_conn_get_status,    /* WC_CONN_GET_STATUS */
	(wlan_conf_handler) rtw_wx_set_region_code,	/* WC_SET_REGION_CODE */
	(wlan_conf_handler) NULL,			/* WC_GET_REGION_CODE */
#ifdef CONFIG_AP_MODE
	(wlan_conf_handler) rtw_wx_set_ap, 			/*   WC_HAPD_SET_AP */
	(wlan_conf_handler) rtw_wx_set_ap_beaocn, 	/*   WC_HAPD_SET_AP_BEACON */
	(wlan_conf_handler) rtw_wx_set_ap_config, 	/*   WC_HAPD_SET_AP_CONFIG */
	(wlan_conf_handler) rtw_wx_set_ap_start, 	/*   WC_HAPD_SET_AP_START */
	(wlan_conf_handler) rtw_wx_get_sta_num,             /* WC_HAPD_GET_STA_NUM */
	(wlan_conf_handler) rtw_wx_get_client_list,             /* WC_HAPD_GET_STA_LIST */
	(wlan_conf_handler) rtw_wx_get_new_sta_wpa_ie,			/*	 WC_HAPD_GET_STA_WPA_IE */
	(wlan_conf_handler) rtw_wx_set_sta_flush,			/*	 WC_HAPD_STA_FLUSH */
	(wlan_conf_handler) rtw_wx_set_sta_remove,			/*	 WC_HAPD_STA_REMOVE */
	(wlan_conf_handler) rtw_wx_set_wps_bcn_ie,			/*	 WC_HAPD_WPS_SET_BCN_IE */
	(wlan_conf_handler) rtw_wx_set_wps_probe_resp_ie,			/*	 WC_HAPD_WPS_SET_PROBE_RESP_IE */
	(wlan_conf_handler) rtw_wx_set_wps_assoc_resp_ie,			/*	 WC_HAPD_WPS_SET_ASSOC_RESP_IE */
	(wlan_conf_handler) rtw_wx_set_encryption,			/*	 WC_HAPD_WPS_SET_ASSOC_RESP_IE */
#endif
}; 
int rtw_wconfig_handler (void *dev, void *command)
{
    struct rtw_wc_command *iw_cmd = (struct rtw_wc_command *)command;

    if (rtw_handlers[iw_cmd->wc_cmd]) {
        return rtw_handlers[iw_cmd->wc_cmd](dev, &iw_cmd->iwcp); 
    }
	
    return -1;
}



